Launch · engineers · marketers · PMs
Staging must not train production
QA buys the product ten times a day. If those Purchases hit the production pixel, the model learns that your office converts at 100%. Then real users look expensive.
Separate ids
1. A staging pixel id (and a staging G- measurement id) costs nothing compared to poisoned ROAS. 2. GTM environments exist to swap those ids. Use them. 3. CAPI access tokens and MP api_secret are per stream; do not reuse production secrets on staging hosts. 4. Adobe: a staging report suite, not the production /b/ss/ suite. 5. Floodlight: a staging activity cat, not the production purchase cat.
Shared production pixels on localhost are how QA trains the model on fake purchases. The ads UI will not label them as QA. It will optimize toward them.
Test flags when you must share an id
1. Meta test_event_code keeps hits in Test Events more or less. Pixellint warns when it is present because leftover codes divert production. 2. GA4 debug_mode and /debug/mp/collect are QA surfaces. Do not point production traffic at the debug URL. 3. Strip flags in prod with a build flag, not a comment. 4. TikTok and others have test event toggles; treat them the same. 5. A test code is not a sandbox graph with fake users. Production tokens plus a test code is still your real pixel id.
If the flag can ship, it will. CI on the production fixture must fail when test_event_code is set. That is a one-line json fixture.
pixellint validate json @fixtures/prod-capi.json --rulepack vendor/meta-conversions-api
# production fixture must not include test_event_code
Hosts and event_source_url
1. event_source_url=http://localhost:3000 in a payload that still hits production is a domain-quality stain. 2. Block prod tokens on non-prod hosts in the client. 3. Preview deploy URLs (Vercel, Netlify) are not your verified domain. 4. SPA staging routes still need a real https URL if the event is marked website. 5. Collect hits from staging should use the staging G- tid, not a hardcoded production tid in a GTM constant.
Vendors compare the host to your verified domain. A week of QA on production CAPI looks like a traffic spike from the office IP with 100% conversion.
GTM preview is not staging
Preview attaches to a draft. Staging is an environment that real QA uses without the preview cookie. Users without the debug cookie get the published container. Shipping based on preview alone is how unpublished tags look fine in QA and missing in production. Publish the staging environment, then test a clean browser.
See GTM preview versus production. Do not use preview as the only staging story.
CI still runs on fixtures
Staging pixels do not replace contract tests. Keep golden Purchase bodies and the cases that must fail. pixellint validate url and pixellint validate json on every PR. A staging pixel that is correctly isolated can still ship Date.now() to Meta. Isolation is not a schema check.
Pixellint is not affiliated with Meta or Google. Separate ids are an ops choice. The packs will happily lint a production pixel URL you should not have fired from staging.
pixellint validate url @fixtures/staging-pixel.txt --rulepack vendor/meta
pixellint validate json @fixtures/staging-capi.json --rulepack vendor/meta-conversions-api
Check the artifact
Paste the pixel URL or JSON body into the
playground. Same engine as
pixellint validate. Nothing leaves the tab.