Engineering

Hybrid mode: when to put the browser pixel back in

Server-side alone covers 100 % of consenting visitors. Hybrid mode adds first-party fbp / _ttp / li_fat_id cookies for better match-rate. Stable event_id dedup is what keeps it from double-counting. Walkthrough of the trade-off and concrete heuristics for when to switch it on per channel.

Reading time: ~6 minPublished: 2026-05-02

The match-rate problem

Server-side dispatch sends events with whatever data your WordPress install has access to: hashed email and phone if the visitor submitted a form, hashed name and address if WooCommerce captured them at checkout, IP and user agent always. That covers a lot of cases but leaves match-rate on the table for one specific group of visitors: those who clicked an ad and have not yet handed over PII.

For those visitors, the platform's primary attribution mechanism is the click-ID stored in a first-party cookie. fbp for Meta, _ttp for TikTok, li_fat_id for LinkedIn, _gcl_aw for Google Ads. Beaconry captures the click-ID from the URL parameter on landing (fbclid, ttclid, etc.) and persists it in nl_ext. That works server-side. But the platforms can do more granular matching when they also see their own first-party cookies, which only their own browser pixel can write.

What hybrid mode actually does

With hybrid mode on for a channel, Beaconry also loads that platform's browser pixel script alongside the server-side dispatch. The browser pixel sets the platform's first-party cookies (fbp, _ttp, li_fat_id), and fires the same event the server is firing, with one critical detail: a stable event_id shared between the two sources.

Concretely, on a purchase event in WooCommerce with hybrid mode on for Meta:

  1. Beaconry generates an event_id at the moment of purchase: a deterministic hash of the WooCommerce order ID. Same value on every retry, same value across browser and server.
  2. Browser fires fbq('track', 'Purchase', {...}, {eventID: 'abc123'}).
  3. Server fires the same Purchase event with event_id: 'abc123' via Meta CAPI.
  4. Meta receives both, deduplicates on event_id, counts as one purchase.

The platform takes whichever event arrived with more matching signals. Browser side has fbp + fbc (first-party cookies that Meta knows). Server side has hashed email + phone + city + zip. With both arriving for the same event_id, the platform merges the data and treats it as one high-quality conversion.

How dedup actually works at each platform

The general pattern is the same, the implementation differs:

  • Meta: deduplicates on event_id + event_name within a 48-hour window. Documented and stable. The most predictable of the three.
  • TikTok: deduplicates on event_id within a 24-hour window. Documented and works as advertised.
  • LinkedIn: idempotency-key based dedup for the Conversions API. The browser tag and server CAPI use the same idempotency key. Works but the docs are sparse, you mostly verify by checking the Campaign Manager counter doesn't double.

GA4 and Google Ads don't have the same dedup pattern because their browser-side and server-side dispatch are typically run as separate properties anyway, so double-counting isn't a concern there in the same shape.

The cost

Real, not negligible:

  • Bytes: ~30 KB extra browser-side per platform you enable hybrid for. Five hybrid-enabled channels = 150 KB additional load. Lighthouse-visible, possibly noticeable on slow connections.
  • Adblock vulnerability for that subset: the browser pixel script gets blocked by adblockers. So for adblock visitors you lose the match-rate boost, you still have the server-side event with hashed PII, but the dedup is single-sided. No worse than off, but no better either.
  • CSP changes: Beaconry's CSP automatically widens when you enable hybrid for a channel (adds the platform's domain to script-src and connect-src). If you have a strict CSP, this is a visible policy change.
  • Privacy posture: the visitor's browser now talks directly to the platform, not just same-origin to your WordPress. Harder to sell as "no third-party tracking", because there is some, even if event_id-deduplicated.

When hybrid wins

  • High-intent purchase campaigns where match-rate is the conversion-attribution bottleneck.
  • Audiences with lower adblock-rates (retail mainstream, 15-20 %).
  • Conversion volumes high enough that 5-10 % match-rate improvement materially changes the campaign's ROAS.
  • Meta specifically: Meta's match-rate is more sensitive to first-party cookies than the other platforms, so hybrid helps most there.

When hybrid loses

  • B2B audiences with high adblock-rates (35-50 %): the hybrid match-rate boost gets eaten by the blocked pixel script anyway.
  • Low-budget campaigns where the absolute match-rate improvement (in conversions) is in the single digits per month.
  • Privacy-positioned brands where the marketing-side tradeoff of "no third-party domains" is part of the value proposition.
  • Strict CSP environments where adding new script-src entries triggers internal review.

Implementation walkthrough in Beaconry

One toggle per channel, no client-side code to write. WordPress Admin → Beaconry → Tracking → [channel] → Hybrid mode. Toggle on, save.

Behind the scenes, Beaconry now: (a) emits the platform's browser pixel script via wp_enqueue_script with defer, (b) sets up a small JS bridge that listens for the same events the server-side path fires, (c) attaches the same stable event_id to both, (d) widens CSP to allow the platform's domain. Visitor sees ~30 KB more JavaScript, platforms see two events with one event_id.

Verification:

  • DevTools Network tab: you should see the platform's pixel script load and the platform's pixel-format request fire on the event.
  • Beaconry Logs tab: server-side event log entry shows the same event_id as the browser-side event in DevTools.
  • Platform's debug view (Meta Test Events, TikTok Test Events, LinkedIn Conversion Manager): event arrives once, not twice. If you see it twice in the platform debug view, something in your event_id generation is non-deterministic.

Recommended starting position

Default hybrid mode off for all channels. Server-side alone covers 100 % of consenting visitors and is faster on the page. Switch hybrid on per channel when you have a specific match-rate problem the channel is causing, Meta's "Match Quality is Poor" warning is the most common trigger, GA4 and TikTok rarely call for it.

Reassess every quarter. The relative value of hybrid mode shifts as platforms tighten or loosen their attribution windows, as adblock rates climb, as your audience composition changes. The toggle is reversible; over-using hybrid mode silently costs you bytes and CSP-cleanliness without buying proportional match-rate.

Take-away

Hybrid mode is not a "more is better" feature. It's a precise tool for one specific problem: improving match-rate on platforms that depend on first-party cookies for attribution. Server-side alone is the right default; hybrid is the right answer when the platform's reporting tells you match-rate is the bottleneck. Stable event_id is what keeps the trade-off honest, the same event sent from two sources, deduplicated to one, with the platform picking the richer signal.