pixellint

Pixels · engineers · marketers

Noscript is a different request

The noscript block is not a comment. Browsers that skip scripts fetch the image inside it. If you also fire the JS tag, you need a story for who counts. Meta's collector uses noscript=1 to mark the image path. Ad blockers are not the same problem as JavaScript being off.

Meta's flag

Meta's image pixel takes noscript=1 so their collector knows this hit did not come from fbq. The documented values are 0 and 1. Treat it as a separate transport, not as a debug switch you leave on in the JS path. A JS-fired /tr with noscript=1 tells Meta the opposite of what happened. A noscript img with noscript=0 looks like a script hit that never ran a script.

Pixellint flags noscript when the value is not 0 or 1. A typo (true, yes, 2) is a real request that Meta may ignore or misfile. The rule id is vendor.meta.param.noscript.invalid. id still has to be numeric and ev still has to be present. noscript=1 does not relax Purchase: cd[value] and cd[currency] as ISO 4217 are still required on ev=Purchase.

When JavaScript is actually off

The img inside noscript loads when the browser does not run scripts: a user disabled JS, a text-mode client, or a locked-down corporate image of Chrome with JS off. A CSP that blocks connect.facebook.net in script-src but allows www.facebook.com in img-src is the same outcome: fbq never runs, the noscript image can. Email and some in-app webviews never run your page JS. Those environments only have the image, if they load images at all.

GTM's noscript iframe is a different object: googletagmanager.com/ns.html?id=GTM-XXXX. That iframe loads a container subset without JS on the parent. It is not Meta's noscript=1, and it is not a bypass for a CSP that also blocks googletagmanager.com. Pixellint's GTM pack requires id on gtm.js, gtag/js, and ns.html. An empty id is a broken fallback, not a privacy feature.

Ad blockers block both

EasyList and uBlock Origin match facebook.com/tr, google-analytics.com/g/collect, and ads.tiktok.com by host. The filter does not care whether the request came from fbq or from an img inside noscript. If the host is listed, both transports die. QA that disables JS and still sees no /tr is often an extension, not a noscript bug.

Confirm with a clean profile: JS off, no extensions, then JS off with uBlock. The first case should show the noscript image. The second should show nothing. Do not spend a sprint rewriting noscript to dodge a list. If the host is blocked, the recovery path is a server event (CAPI) or a collector on a first-party host you actually operate, not a second img to the same blocked host.

Dedup against the script

A user can, in theory, hit both: JS on, noscript also in the DOM (browsers that run JS skip noscript, so this is rare on desktop). The realistic double path is a tag manager that fires the image tag always, plus fbq. Then you get two PageView hits with different transports and no shared event_id. Meta will count two events unless you send the same event_id on both and they collapse.

Most teams only need noscript on the base PageView pixel, not on every custom event they never fire without JS. AddToCart from a noscript image on a page that cannot add to cart without JS is theatre. Purchase from noscript on a thank-you page is more defensible, and then you still need value, currency, and a dedup id if CAPI also fires.

Pinterest and Google Ads image fallbacks

Pinterest's tag also takes noscript as 0 or 1 on ct.pinterest.com. Same idea, different host. Google Ads conversion image pixels put script=0 on the query to mark the image fallback; guid=ON is what the generated tag sends; conversion_id lives in the path; label is expected so the hit lands on a conversion action rather than the account. Those fields are not Meta's noscript=1. Do not copy noscript=1 onto googleadservices.com.

When you validate, treat each vendor's image fallback as its own URL. pixellint validate url on the Meta img, then on the Google Ads img, then on ns.html. One HAR with three hosts is three artifacts. A single noscript block that concatenates three img tags is three requests and three contracts.

Check the artifact

Paste the pixel URL or JSON body into the playground. Same engine as pixellint validate. Nothing leaves the tab.