Blog · Meta click id
Meta _fbc Is Empty Unless fbclid Hits the Landing Page
Hybrid Meta setups assume the server can rebuild click matching from cookies and hashed email. Meta documents a simpler gate: fbclid has to appear on the landing URL, or land in _fbc or backend storage, before Purchase CAPI fires. Skip that hop and fbc is empty even when the JSON validates.
Teams ship CAPI with a worker that hashes email at checkout and posts user_data.fbc from a column named click_id. Test Events shows green when em matches. Ads Manager still under-reports click-through purchases because fbc never contained a real ClickID. The miss is not hashing. It is the landing hop that never persisted fbclid.
This is the dated failure mode around redirect chains, hosted checkout, and sGTM collectors that read cookies on the wrong host. The contract page for cookie shape lives in /docs/fbp-fbc/. This post is the market fact: Meta matching expects fbclid on the first page request you control, not only on the ad click URL Meta generated.
What Meta calls ClickID
Meta appends fbclid to the landing page URL after an ad click. Example URL with ClickID: https://example.com/?fbclid=IwAR2F4-dbP0l7Mn1IawQQGCINEz7PYXQvwjNwB_qa2ofrHyiLjcbCRxTDMgk. The Conversions API accepts that value inside user_data.fbc when formatted, or inside the _fbc browser cookie when the pixel or your server stored it correctly.
Meta recommends always sending _fbc and _fbp browser cookie values in the fbc and fbp event parameters when available, and refreshing the profile with the latest value whenever possible. fbc is not a hash of fbclid. It is a formatted string: version.subdomainIndex.creationTime.fbclid, where creationTime is Unix time in milliseconds when _fbc was stored, or when you first observed the fbclid value if you never wrote the cookie.
If the _fbc cookie is not available because there is no Meta Pixel on the website, Meta still allows fbc on the CAPI event when an fbclid query parameter is in the URL of the current page request. Server-side workers do not get that URL on Purchase unless you copied it forward. That sentence is the whole bug class for hosted checkout.
Where fbclid dies before CAPI
Retrieve from fbclid URL query parameter: whenever present, obtain the parameter server-side by reading the HTTP request URL query string on the landing hit. That is the first-party hop you own. If the user lands on www.example.com with fbclid and checkout completes on shop.example.com without forwarding the query string, the checkout worker never sees fbclid unless you stored it on www.
Marketing redirect chains strip query parameters when a click tracker bounces through three domains before the advertiser site. UTM parameters sometimes survive while fbclid does not, which is how analytics still shows a session while Meta loses the click. Apex to www redirects that drop the query string produce the same split: GA4 sees traffic, fbc is empty on Purchase CAPI.
Safari ITP caps script-written cookies that look like click-id jars. Chrome may keep _fbc longer. A returning Safari buyer can checkout with hashed email and empty fbc because fbclid never got persisted server-side when the landing cookie expired. CAPI is the pipe for blocked-pixel users; it still needs the click id you should have copied on first landing.
Store ClickID before the thank-you POST
Meta Store ClickID guidance: set formatted ClickID in the _fbc cookie in the HTTP response once retrieved from fbclid or _fbc. Only set the cookie if _fbc does not exist and ClickID came from fbclid, or if fbclid in the URL is not equal to the value in the existing _fbc cookie. As an alternative, store formatted ClickID in backend storage and send the most recent value obtained from the URL query parameter when present.
Backend storage is the durable fix for cross-domain checkout. On first landing, read fbclid, mint fbc as fb.1.{landedAtMs}.{fbclid}, attach it to the session or order record you already use for cart id, and POST that string on Purchase CAPI even when document.cookie on the thank-you page is empty. Meta documents broken redirects in Pixel Support; the operational fix is persist on landing, not rebuild from memory on checkout.
Do not paste raw fbclid into user_data.fbc. Meta format expects the fb. prefix and millisecond timestamp. A CAPI payload with fbc equal to IwAR... validates as JSON and fails matching rules. Pixellint flags vendor.meta-conversions-api.body.user_data.fbc.invalid on the wrong shape. A well-formed fbc built from a fbclid you never captured is still a miss.
Landing capture the checkout worker expects
Read fbclid on the landing host. Checkout on another host does not inherit the query string.
// Landing middleware (www.example.com)
const fbclid = new URL(req.url).searchParams.get('fbclid');
if (fbclid) {
const landedAtMs = Date.now();
const fbc = `fb.1.${landedAtMs}.${fbclid}`;
session.click = { fbclid, fbc, landedAtMs };
// Optional: Set-Cookie _fbc=... on this host
}
// Purchase CAPI (shop.example.com): WRONG without session.click
user_data.fbc = cookies._fbc; // often empty here
The wrong pattern reads _fbc only on the thank-you host. Hosted checkout, Shopify pay domains, and Stripe redirect flows split registrable domains by design. The pixel on the landing page may have written _fbc on www, but the server POST fires from shop where that cookie was never set unless Domain=.example.com was configured and the browser still has the jar.
sGTM and first-party collectors can read _fbc if the tag runs on the same site the user landed on and cookies are forwarded into the event payload. Collectors on a subdomain that never saw the landing request still emit Purchase with em and no fbc. Dual-pipe dedup on event_id does not fix matching when both pipes lack ClickID.
Rebuild fbc at checkout from order metadata, not from wishful cookie reads. If session.click.fbc exists, send it. If only fbclid exists, rebuild with the landing timestamp you stored, not Date.now() at purchase time, unless Meta never saw an earlier value. Using purchase time changes creationTime and can weaken join consistency.
Pixel plus CAPI is two hops, not one
When Meta Pixel runs on the landing page, it can store ClickID in _fbc automatically once available. CAPI workers still need that value on the server event for users who block the pixel. Omit fbc on CAPI because the pixel already sent it leaves blocked-browser purchases on email and IP alone.
Advanced matching on fbq is not a substitute for fbc on the server payload. Send both pipes the cookies you have. If the server has fbc and the pixel does not, the blocked-pixel user still joins. If neither has fbc because fbclid died at redirect, no cookie format saves you.
Event Match Quality and Dataset Quality API scores will show missing match keys, but Events Manager Test Events can look fine when em hash is correct. Pull match_key_feedback on a schedule. Empty fbc with strong em is the signature of a landing-hop bug, not a normalization bug.
Checklist
- On first landing, read fbclid from the query string server-side. Persist fbclid and formatted fbc on the session or order.
- Forward fbclid through every redirect to checkout. curl -sIL the paid URL and confirm fbclid survives.
- On Purchase CAPI, set user_data.fbc from stored fbc or rebuild fb.1.{landedAtMs}.{fbclid}. Do not send raw fbclid.
- Send user_data.fbp when the _fbp cookie exists on the landing host. Do not mint fake fbp on the server.
- Reuse event_id on pixel and CAPI for dedup. Matching still needs fbc or fbclid-derived fbc on the server event.
- Lint the POST body with vendor/meta-conversions-api before production. HTTP 200 is not a click join.
If the _fbc cookie is not available because there is no Meta Pixel running on the website, it is still possible to send the fbc event parameter with the Conversion API event if an fbclid query parameter is in the URL of the current page request.
Meta Conversions API: fbp and fbc parameters
What to verify before blaming match quality
Log landing URL query parameters on the edge, not only checkout fields. If fbclid is absent on landing logs for paid traffic, fix redirects before you tune hashing.
Compare pixel PageView with fbclid on the same session id as Purchase CAPI. If PageView never saw fbclid, CAPI will not invent it.
Pixellint is not affiliated with Meta. Passing validate json means the fbc string matches Meta documented shape. It does not mean fbclid reached the landing page. This post is the hop between the ad click and that shape.
Sources
Contract pages
The dated argument is above. These pages are the field lists.