Open source

One wrong line in the cookie code, and the conversion goes to another ad.

fbc-guard reads the code on your landing page that stores Meta click IDs and finds the patterns that send conversions to the wrong ad or make Events Manager report a modified fbclid. It reads source only: it does not run the code and sends nothing to Meta.

Why this code needs checking

When someone clicks a Meta ad, the landing page URL carries an fbclid parameter. Your page stores it in a first-party _fbc cookie in the form fb.subdomainIndex.creationTime.fbclid, and later events send that value to Meta.

Meta's reference page on the fbp and fbc parameters sets out the requirements: the click ID is case sensitive and must not be modified, creationTime is in milliseconds, and a new value should be written when the fbclid in the URL differs from the one stored in the cookie.

Hand-written versions of this code tend to go wrong in exactly those places. Nothing breaks on the page and visitors notice nothing; only the attribution in your reports is quietly wrong. Each rule below states its basis: stated by Meta, derived from a general requirement Meta states, or a mistake observed in real implementations.

The four parts of a Meta _fbc cookie: fb prefix, subdomainIndex, creationTime in milliseconds, the fbclid as received

The seven rules

FBC-01 A new click ID overwrites the old one

Writing the cookie only when it does not exist means a returning visitor who clicks a different ad still sends the earlier click ID, and the conversion is attributed to the earlier ad. Basis: stated by Meta.

FBC-02 Do not decode it twice

Reading fbclid from the URL already decodes it. Calling decodeURIComponent on it again changes the value. Basis: derived.

FBC-03 Do not change its case

The click ID is case sensitive; lowercasing or uppercasing it produces a different value. Basis: stated by Meta.

FBC-04 Do not truncate it

Cutting the click ID with slice or substring sends a value that is no longer the original. Basis: derived.

FBC-05 _fbc creationTime in milliseconds

A seconds timestamp such as Date.now()/1000 in the statement that builds the _fbc value fails, including when it is stored in a variable first or written inside a template literal. Basis: stated by Meta.

FBC-06 Do not hard-code subdomainIndex

A literal digit breaks on domains at a different level; derive it from the hostname. Basis: observed in practice, not a Meta requirement.

FBP-01 _fbp creationTime in milliseconds

The same check as FBC-05, for the _fbp cookie. Basis: stated by Meta.

Verdicts and exit codes

Every rule returns one of these results. The command line exit code can sit directly in front of a deploy.

ResultMeaningExit code
passNone of the known mistakes were found0
failAt least one rule found a known mistake1
unknownThe variable holding the URL click ID could not be identified, so this rule gives no verdict0
not_applicableNo _fbc in what was scanned. Nothing was judged; this is not a pass0
selftest failedThe checker failed its own controls and gives no verdict2

How to use it

Requires Node.js 18 or later. Point it at a live landing page and it also fetches same-origin scripts; cross-origin scripts are listed but never fetched:

npx -y -p mcp-server-fbc-guard fbc-guard https://your-landing-page.example/

Or check built files before they ship:

fbc-guard ./dist/index.html ./dist/js/tracking.js

As an MCP server, an assistant can check tracking code while it is writing it:

{"mcpServers":{"fbc-guard":{"command":"npx","args":["-y","mcp-server-fbc-guard"]}}}

Two tools: check_fbc_code checks a piece of code, check_fbc_url fetches a page and its same-origin scripts first. The server runs its own selftest at startup and refuses to start if it fails.

Limitations and licence

MIT licensed. This is static analysis of source text, not execution. A pass means none of the known mistakes were found in the shapes the tool recognises, not that the code is correct. Minified, bundled or obfuscated code and code assembled at runtime can hide a mistake. Tracking code inside a tag manager container, a cross-origin script or a server-side integration is not visible to the scan. To confirm what is actually sent, load the page in a browser with an old _fbc cookie set and a realistic fbclid in the URL, and compare the value your code sends with the URL value character by character.

GitHubnpm

Related reading

Click IDs are one part of a tracking setup:

Track First, Scale Later: Pixel and CAPI deduplication Meta Ads From Scratch Tracking and attribution setup

FAQ

Why does Events Manager say my fbclid was modified?
The click ID in the fbc parameter differs from the original value in the ad click URL. Common causes are decoding fbclid a second time, changing its case, truncating it, or keeping an old cookie when a returning visitor clicks a new ad. fbc-guard finds each of these patterns.

Should _fbc creationTime be in seconds or milliseconds?
Milliseconds. Meta's format uses a millisecond timestamp, the value of Date.now(), not divided by 1000.

I use the Meta Pixel. Do I need this?
If the Pixel alone writes _fbc, the scan reports not applicable. The checks matter for code that writes the cookie itself or reads fbclid from the URL to send through the Conversions API.

Does it send data to Meta?
No. It reads page source and same-origin script files. It does not execute the code and sends nothing anywhere.

If you would rather someone else did this

Tracking and attribution setup is part of what we deliver. If your ad numbers do not add up, describe your situation and we will tell you straight.

Chat on Telegram
Chat on TG