fix(analytics): bypass Cloudflare Rocket Loader for Mixpanel snippet#5
Conversation
Root cause of "no data in Mixpanel": Cloudflare Rocket Loader rewrites every inline <script>, changing type="text/javascript" into type="<hash>-text/javascript". The browser then refuses to execute it, so the Mixpanel IIFE + mixpanel.init(...) never run — the SDK is never injected and zero events are sent. The fix is the standard Cloudflare escape hatch: data-cfasync="false" tells Rocket Loader to leave this script alone and let the browser run it immediately, in document order. Verified the rest of the chain is healthy: - SDK URL mixpanel-2-latest.min.js → HTTP 200 (fixed in PR #4) - api-js.mixpanel.com/track/ → returns 1 (accepts events) - token/region correct (US decide endpoint 200) So this is the last remaining blocker.
Deploying fx-lab with
|
| Latest commit: |
0a16886
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://b55e8eec.fx-lab.pages.dev |
| Branch Preview URL: | https://fix-mixpanel-rocket-loader.fx-lab.pages.dev |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0a168866da
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| data-cfasync="false" tells Cloudflare Rocket Loader to leave this script alone (run immediately, in document order). | ||
| Without it, Rocket Loader rewrites <script type> and the inline init never executes → zero events reach Mixpanel. --> | ||
| <script data-cfasync="false"> | ||
| (function(f,b){if(!b.__SV){var e,g,i,h;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b){var c=b.split(".");2==c.length&&(b=b[c[0]],a=c[0]]=a[c[0]]||{},a=a[c[0]])}b._q.push({a:d});f("track");f("identify");f("reset");f("register");f("alias");f("people.set");f("people.increment");f("track_charge");f("append");b._i[d]={};a&&"function"==typeof a&&(b._i[d]=a)};b.__SV=1.2;e=f.createElement("script");e.type="text/javascript";e.async=!0;e.src="https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";g=f.getElementsByTagName("script")[0];g.parentNode.insertBefore(e,g)}})(document,window.mixpanel||[]); |
There was a problem hiding this comment.
Restore valid Mixpanel bootstrap syntax
In browsers this inline script now fails to parse because the assignment expression was changed to a=c[0]]=..., so none of the script block runs, including mixpanel.init(...). In the deployed analytics path this leaves window.mixpanel uninitialized and keeps all events at zero despite the Rocket Loader opt-out; the same typo is present in web/index.html as well.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR aims to restore Mixpanel analytics by preventing Cloudflare Rocket Loader from rewriting (and effectively disabling) the inline Mixpanel bootstrap snippet, using Cloudflare’s data-cfasync="false" escape hatch.
Changes:
- Add
data-cfasync="false"to the inline Mixpanel<script>tag so Rocket Loader won’t rewrite/defer it. - Expand the inline comment explaining why Rocket Loader must be bypassed for this snippet.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| web/index.html | Adds Rocket Loader bypass + explanatory comment to keep the inline Mixpanel init executing. |
| site/index.html | Same Rocket Loader bypass + explanatory comment for the site variant of the HTML. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| data-cfasync="false" tells Cloudflare Rocket Loader to leave this script alone (run immediately, in document order). | ||
| Without it, Rocket Loader rewrites <script type> and the inline init never executes → zero events reach Mixpanel. --> | ||
| <script data-cfasync="false"> | ||
| (function(f,b){if(!b.__SV){var e,g,i,h;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b){var c=b.split(".");2==c.length&&(b=b[c[0]],a=c[0]]=a[c[0]]||{},a=a[c[0]])}b._q.push({a:d});f("track");f("identify");f("reset");f("register");f("alias");f("people.set");f("people.increment");f("track_charge");f("append");b._i[d]={};a&&"function"==typeof a&&(b._i[d]=a)};b.__SV=1.2;e=f.createElement("script");e.type="text/javascript";e.async=!0;e.src="https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";g=f.getElementsByTagName("script")[0];g.parentNode.insertBefore(e,g)}})(document,window.mixpanel||[]); |
| data-cfasync="false" tells Cloudflare Rocket Loader to leave this script alone (run immediately, in document order). | ||
| Without it, Rocket Loader rewrites <script type> and the inline init never executes → zero events reach Mixpanel. --> | ||
| <script data-cfasync="false"> | ||
| (function(f,b){if(!b.__SV){var e,g,i,h;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b){var c=b.split(".");2==c.length&&(b=b[c[0]],a=c[0]]=a[c[0]]||{},a=a[c[0]])}b._q.push({a:d});f("track");f("identify");f("reset");f("register");f("alias");f("people.set");f("people.increment");f("track_charge");f("append");b._i[d]={};a&&"function"==typeof a&&(b._i[d]=a)};b.__SV=1.2;e=f.createElement("script");e.type="text/javascript";e.async=!0;e.src="https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";g=f.getElementsByTagName("script")[0];g.parentNode.insertBefore(e,g)}})(document,window.mixpanel||[]); |
The bootstrap IIFE shipped since 7c95a83 was a hand-edited variant with a structurally broken init stub: it called b._q.push(...) but only ever initialized b._i (never b._q), so every mixpanel.init(...) threw 'TypeError: Cannot read properties of undefined (reading push') before any tracking method (track/identify/people.set/...) could be stubbed onto the object. Result: zero events, even with a valid SDK URL and Rocket Loader bypass. PR #6 fixed one symptom (the a=c[0]] syntax typo from #5), but the underlying _q/_i logic bug remained — flagged again as P1 by Codex review on #6. Fix: replace the whole IIFE with Mixpanel's official snippet verbatim from https://docs.mixpanel.com/docs/tracking-methods/sdks/javascript. The official stub stubs out all methods (track, identify, people.*, ...) and records the init call via b._i.push([...]) — matching the SDK's own contract. Verified by executing the extracted <script> block in Node with a DOM mock: - mixpanel._i receives the init call - mixpanel.track / identify / people.set are all functions - No TypeError, no SyntaxError Same snippet in site/index.html and web/index.html. data-cfasync="false" and the existing mixpanel.init(...) config line are preserved.
* fix(analytics): restore Mixpanel IIFE syntax broken in PR #5 PR #5 (Rocket Loader bypass) accidentally introduced a typo in the Mixpanel bootstrap IIFE: a[c[0]]= became a=c[0]]=, which is a JS SyntaxError (Unexpected token ']'). The whole <script> block fails to parse, so mixpanel.init() never runs and no events are sent — the Rocket Loader fix was correct but got masked by this regression. Confirmed via `node --check` on the extracted <script> block: SyntaxError on the merged code, OK after this fix. Reported by Codex (P1) and Copilot review on PR #5. Only the two bytes a[ → a= are changed; nothing else. * fix(analytics): replace corrupted Mixpanel stub with official snippet The bootstrap IIFE shipped since 7c95a83 was a hand-edited variant with a structurally broken init stub: it called b._q.push(...) but only ever initialized b._i (never b._q), so every mixpanel.init(...) threw 'TypeError: Cannot read properties of undefined (reading push') before any tracking method (track/identify/people.set/...) could be stubbed onto the object. Result: zero events, even with a valid SDK URL and Rocket Loader bypass. PR #6 fixed one symptom (the a=c[0]] syntax typo from #5), but the underlying _q/_i logic bug remained — flagged again as P1 by Codex review on #6. Fix: replace the whole IIFE with Mixpanel's official snippet verbatim from https://docs.mixpanel.com/docs/tracking-methods/sdks/javascript. The official stub stubs out all methods (track, identify, people.*, ...) and records the init call via b._i.push([...]) — matching the SDK's own contract. Verified by executing the extracted <script> block in Node with a DOM mock: - mixpanel._i receives the init call - mixpanel.track / identify / people.set are all functions - No TypeError, no SyntaxError Same snippet in site/index.html and web/index.html. data-cfasync="false" and the existing mixpanel.init(...) config line are preserved.
Symptom
PR #4 fixed the SDK URL, but Mixpanel still shows zero data after deploy.
Root cause — Cloudflare Rocket Loader
The live HTML shows Rocket Loader rewrote our analytics
<script>:Rocket Loader changes every inline script's
typeto a hashed-prefixed variant, which the browser treats as unknown → does not execute. It then defers execution to its own loader.For the Mixpanel snippet this is fatal: the IIFE that injects the SDK never runs, so
window.mixpanelis never initialized, the SDK is never loaded, and every downstreammixpanel.track(...)call is a no-op. Zero events reach Mixpanel.Evidence the rest of the chain is fine
Tested directly (bypassing Rocket Loader):
mixpanel-2-latest.min.js→ HTTP 200 (PR fix(analytics): load working Mixpanel SDK (was 404) + confirm Rybbit removed #4)api-js.mixpanel.com/track/→ POST returns `1` (Mixpanel accepted the event)decideendpoint 200 → token/region (US) correctSo the only remaining blocker is Rocket Loader suppressing the inline init.
Fix
Add
data-cfasync=\"false\"— Cloudflare's official escape hatch that says "run this script normally, don't touch it":Applied to both `site/index.html` and `web/index.html`. Also expanded the comment to explain why the attribute is there, so nobody removes it later.
After merge