Skip to content

Click identifiers (gclid / gbraid / wbraid)

Click identifiers are how Google Ads matches a conversion to the ad click that drove it. There are three of them and they cover three different attribution paths.

IdentifierWhere it shows upWhy it exists
gclidStandard ad clicks: web search, display, most paid trafficHas been the canonical Google Ads click identifier for years.
gbraidiOS in-app clicks landing on the webApple’s ATT framework restricts identifier passing; gbraid is Google’s web-side compatible token for those flows.
wbraidiOS in-app clicks where ATT consent was deniedCarries less data than gbraid but enables aggregated attribution.

If your ads run on web search, you’ll see gclid everywhere. If they also run iOS app installs that drive web traffic, the other two start showing up. Trackbridge captures all three the same way and forwards all three.

When createBrowserTracker runs (typically once per page load), it reads window.location.search and looks for these query parameters. Whichever it finds, it puts in the tracker’s internal state.

https://yoursite.com/landing?utm_source=google&gclid=Cj0KCQ...

After init, tracker.getClickIdentifiers() returns:

{ gclid: 'Cj0KCQ...' }

If the URL has multiple of gclid, gbraid, wbraid, the SDK keeps each one. Real-world traffic only has one at a time, but the SDK doesn’t enforce that.

After capture, if clickIdentifierStorage === 'cookie' (the default) and consent permits, the SDK writes one cookie per identifier:

_tb_gclid=Cj0KCQ...; Secure; SameSite=Lax; Path=/; Expires=<+90d>

Domain= is added if you set cookieDomain on the tracker config — useful for cross-subdomain attribution (www.example.com capturing on landing, app.example.com reading on conversion). See Cross-subdomain tracking.

The cookies are first-party (your domain), Secure (HTTPS only), and SameSite=Lax (sent on top-level navigations but not third-party iframes). They are not HttpOnly because the SDK has to read them from JavaScript.

The full table of cookie attributes is on the Cookies reference page.

When consentMode: 'v2' is configured, the SDK only writes the cookies if ad_storage is 'granted'. Until that happens, captured values live only in memory.

The flow:

  1. User lands on ?gclid=Cj0KCQ.... SDK captures gclid into memory.
  2. CMP banner is shown. User has not interacted yet — ad_storage is unknown, treated as not-granted.
  3. SDK does not write _tb_gclid cookie.
  4. User clicks “Accept” on the banner. CMP fires tracker.updateConsent({ ad_storage: 'granted', ... }).
  5. SDK writes _tb_gclid cookie at this point — the in-memory value is persisted.
  6. On a later page load, the SDK reads the cookie and re-hydrates the in-memory state, even without a gclid in the URL.

If the user clicks “Decline”, the in-memory value is held for the lifetime of the tab and discarded on close. Subsequent page loads have no record of the click.

This is the right GDPR/Consent Mode v2 behavior. See Consent Mode v2.

The browser tracker captures click IDs. The server tracker needs them too — it has no view of the URL the user landed with. Forward them with whatever request creates the order:

import { tracker } from '@/lib/tracker.client';
const clickIds = tracker.getClickIdentifiers();
await fetch('/api/checkout', {
method: 'POST',
body: JSON.stringify({ ...orderInput, clickIds }),
});

Store the IDs alongside the order so they’re available later, when the conversion fires (often from a webhook, hours after the user closes their browser):

const order = await db.orders.create({
...orderInput,
gclid: clickIds.gclid ?? null,
gbraid: clickIds.gbraid ?? null,
wbraid: clickIds.wbraid ?? null,
});

When the server-side conversion fires:

await serverTracker.trackConversion({
label: 'purchase',
transactionId: order.id,
gclid: order.gclid ?? undefined,
gbraid: order.gbraid ?? undefined,
wbraid: order.wbraid ?? undefined,
// ...
});

If you don’t forward, the server-side conversion still fires but Google can’t attribute it to a click. It still helps with the conversion count (the dedup partner of the browser fire), but not with attribution beyond what the browser-side fire already carried.

  • It does not call the Google Ads API to validate the click. The gclid you have is the one Google gave the user; the SDK trusts that.
  • It does not decay or rotate values. A 90-day-old gclid is sent as-is. Google’s matcher decides if it’s still attributable.
  • It does not capture other tracking parameters (fbclid, msclkid, etc.). Trackbridge is a Google Ads / GA4 SDK; the names are hardcoded to the three Google identifiers.