Environment
@nuxt/scripts 1.2.1 (registry entry unchanged in 1.3.0), Nuxt 4, Nitro cloudflare_module preset (Cloudflare Workers)
- Snapchat pixel registered at runtime via
useScriptSnapchatPixel({ id }), bundling enabled via runtimeConfig.public.scripts.snapchatPixel.scriptOptions.bundle = true
Bug
Bundling (self-hosting) the Snapchat pixel breaks it. scevent.min.js derives the host of its own <script> URL from an Error().stack trace at runtime, and when that host is not sc-static.net it assumes it is running behind Snap's CAPI gateway and loads its config from the serving origin:
GET https://<page-host>/config/<tld-of-page-hostname>/<pixel-id>.js?v=3.59.0-...
On a normal Nuxt app that path 404s (and Nitro error responses carry X-Content-Type-Options: nosniff, so the browser refuses the response as a script even when the 404 page renders). The SDK only falls back to tr.snapchat.com/config/… after a ~5 s timeout, and that fallback is exactly the third-party request that tracking blockers kill — so for many visitors the pixel never initializes at all.
Observed live: https://imleavinit.no/ (bundled scevent.min.js served from /_scripts/assets/…) requested https://imleavinit.no/config/no/<pixel-id>.js → 404 → NS_ERROR_CORRUPTED_CONTENT / MIME-type block in Firefox.
Evidence (de-minified scevent.min.js)
var S = y(function () { // own script URL, extracted from a stack trace
return m().split("\n")[0].replace(/^.*(http(s){0,1}:\/\/.*\.js):[0-9]+.*$/, "$1");
}, p); // fallback p = "https://sc-static.net/scevent.min.js"
var xe = y(() => new URL(S).host, s); // s = "sc-static.net"
// config loader — i = "/config/<tld>/<id>.js?v=..."
qr(xe !== s ? v + xe + i : De(i)); // v = "https://", De() → https://tr.snapchat.com + path
<tld> is literally hostname.split('.').pop() of the page.
Why first-party proxy mode doesn't help
The build-time AST rewriting replaces domain literals (sc-static.net → /_scripts/p/sc-static.net, …), and the runtime patches match third-party domains in URLs. A host recovered from a stack trace is reachable by neither: the SDK's first config request still goes to the page origin (not /_scripts/p/…), 404s, and only then times out into the direct tr.snapchat.com fallback — which defeats the proxy's purpose anyway.
Suggested fix
Either:
- Drop the
bundle: true capability for snapchatPixel in the registry (bundling produces a strictly worse outcome than loading from sc-static.net), or
- Add an
sdkPatches entry for snapchatPixel that pins the SDK's origin detection to sc-static.net, and/or have the proxy handler answer the CAPI-gateway convention (/config/<tld>/<id>.js, plus the SDK's other origin-relative endpoints like /cm/i, /cm/si) when snapchatPixel proxying is enabled.
Workaround
snapchatPixel: { scriptOptions: { bundle: false } } — load the SDK from sc-static.net so its origin detection matches and config loads from tr.snapchat.com directly.
Environment
@nuxt/scripts1.2.1 (registry entry unchanged in 1.3.0), Nuxt 4, Nitrocloudflare_modulepreset (Cloudflare Workers)useScriptSnapchatPixel({ id }), bundling enabled viaruntimeConfig.public.scripts.snapchatPixel.scriptOptions.bundle = trueBug
Bundling (self-hosting) the Snapchat pixel breaks it.
scevent.min.jsderives the host of its own<script>URL from anError().stacktrace at runtime, and when that host is notsc-static.netit assumes it is running behind Snap's CAPI gateway and loads its config from the serving origin:On a normal Nuxt app that path 404s (and Nitro error responses carry
X-Content-Type-Options: nosniff, so the browser refuses the response as a script even when the 404 page renders). The SDK only falls back totr.snapchat.com/config/…after a ~5 s timeout, and that fallback is exactly the third-party request that tracking blockers kill — so for many visitors the pixel never initializes at all.Observed live:
https://imleavinit.no/(bundledscevent.min.jsserved from/_scripts/assets/…) requestedhttps://imleavinit.no/config/no/<pixel-id>.js→ 404 →NS_ERROR_CORRUPTED_CONTENT/ MIME-type block in Firefox.Evidence (de-minified scevent.min.js)
<tld>is literallyhostname.split('.').pop()of the page.Why first-party proxy mode doesn't help
The build-time AST rewriting replaces domain literals (
sc-static.net→/_scripts/p/sc-static.net, …), and the runtime patches match third-party domains in URLs. A host recovered from a stack trace is reachable by neither: the SDK's first config request still goes to the page origin (not/_scripts/p/…), 404s, and only then times out into the directtr.snapchat.comfallback — which defeats the proxy's purpose anyway.Suggested fix
Either:
bundle: truecapability forsnapchatPixelin the registry (bundling produces a strictly worse outcome than loading fromsc-static.net), orsdkPatchesentry forsnapchatPixelthat pins the SDK's origin detection tosc-static.net, and/or have the proxy handler answer the CAPI-gateway convention (/config/<tld>/<id>.js, plus the SDK's other origin-relative endpoints like/cm/i,/cm/si) when snapchatPixel proxying is enabled.Workaround
snapchatPixel: { scriptOptions: { bundle: false } }— load the SDK fromsc-static.netso its origin detection matches and config loads fromtr.snapchat.comdirectly.