Skip to content

fix(meta-pixel): let a pre-load consent call replace the queued default - #930

Merged
harlan-zw merged 1 commit into
nuxt:mainfrom
felixgabler:fix/meta-pixel-preload-consent
Sep 28, 2026
Merged

harlan-zw merged 1 commit into
nuxt:mainfrom
felixgabler:fix/meta-pixel-preload-consent

Conversation

@felixgabler

Copy link
Copy Markdown
Contributor

🔗 Linked issue

resolves #928

📚 Description

With defaultConsent: 'denied', clientInit queues ['consent', 'revoke'] ahead of init and PageView. A consent.grant() made before fbevents.js loads is appended behind it. fbevents replays the queue in order and stops at the revoke, so the grant never runs and nothing is sent. More detail and a trace are in the issue.

This change touches only the stub. Before fbevents has loaded, a consent call removes any queued consent command and puts the new one at the head of the queue. Consent is a state rather than an event, so the latest decision made before load is the one that applies before init. Once callMethod exists, calls go straight to fbevents as before.

That matches how fbevents behaves after load: commands held while consent is revoked are sent on grant, and a revoke holds everything queued after it.

Before, in the playground repro from the issue (Chrome, window.fbq.queue traced):

queue before load: consent,revoke / init / track,PageView / consent,grant
after load:        stuck at init / track,PageView / consent,grant
requests:          none

After:

queue before load: consent,grant / init / track,PageView
after load:        empty
requests:          signals/config, /tr ev=PageView, /tr ev=Lead

We also run the same change as a local patch on 1.3.9 in production builds. It sends events for visitors who had already consented, sends nothing while consent is undecided, and sends nothing when consent is withdrawn before the pixel finishes loading.

Tests in test/nuxt-runtime/consent-default.nuxt.test.ts:

  • The existing Meta test expected pre-load grant() then revoke() to both be appended. It now expects only the latest consent, at the head of the queue.
  • New: grant() before load replaces defaultConsent: 'denied'.
  • New: once callMethod exists, consent calls go straight to it.

Both new tests fail on main without the change. The file passes (30 tests) with it, and eslint is clean.

One thing we are unsure about: this only reorders consent commands in the pre-load queue. If there is a reason to keep strict call order there that we have not thought of, we are happy to adjust.

Thanks for the module and for looking at this.

I investigated this with help from an AI coding assistant (Claude Code), which also drafted this text. I reviewed it, and the results above come from real runs.

@vercel

vercel Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

@felixgabler is attempting to deploy a commit to the Nuxt Team on Vercel.

A member of the Team first needs to authorize it.

@harlan-zw

harlan-zw commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

🤖 MERGED

Harlan Agent Kit posted this automated review. It is not Harlan's personal review or approval. AI open source policy. Last updated: 2026-09-28 12:59 UTC.

GitHub merged this pull request.

  • Required check "Vercel" fails on the pull request head commit. View code Next: Read the failing "Vercel" job logs on the pull request, fix the cause, and run only the focused check.

The pull request closed.

@pkg-pr-new

pkg-pr-new Bot commented Sep 25, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@nuxt/scripts@930

commit: 4d6b8d6

@coderabbitai

coderabbitai Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 3b4729d4-132d-46fb-ad14-c42836c11af0

📥 Commits

Reviewing files that changed from the base of the PR and between 4bb52cc and 4d6b8d6.

📒 Files selected for processing (2)
  • packages/script/src/runtime/registry/meta-pixel.ts
  • test/nuxt-runtime/consent-default.nuxt.test.ts

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

The Meta Pixel stub now removes queued consent calls before adding a new consent call at the front of the queue. It continues to append other commands normally. Tests cover consent calls made before loading, replacement of the default denied call, and forwarding to callMethod after it becomes available.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 4d6b8

No concrete unresolved issue has been established; the change is mergeable after normal checks.

Architecture Summary

Architecture risk: 🔵 Low · up to 4d6b8

The change affects 2 systems.

Changed systems: packages/script, test

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — packages/script (library) was modified; 1 changed file maps to changed impact.
  • observed — test (service) was modified; 1 changed file maps to changed impact.

Before / after behavior

  • observed — Modified behavior in packages/script/src/runtime/registry/meta-pixel.ts: The fbq stub now removes every queued consent call and prepends the latest consent call, rather than letting consent calls follow the ordinary queue path. Other commands remain queued in order.
  • observed — Modified behavior in test/nuxt-runtime/consent-default.nuxt.test.ts: Replaces the test that cleared the queue and expected both consent actions with one asserting that pre-load grant() followed by revoke() leaves only revoke at the queue head, before init and PageView.
  • observed — Modified behavior in test/nuxt-runtime/consent-default.nuxt.test.ts: Adds coverage that pre-load grant() replaces the denied default consent entry and appears before initialization and the PageView and Lead tracking entries.
  • observed — Modified behavior in test/nuxt-runtime/consent-default.nuxt.test.ts: Adds coverage that after callMethod is set, grant() is forwarded to it, while the queued default revoke remains.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: allowing a pre-load consent call to replace the queued default consent decision.
Description check ✅ Passed The description directly explains the queued consent issue, the stub behavior change, expected runtime behavior, linked issue, and test coverage.
Linked Issues check ✅ Passed The change satisfies the coding requirements in #928. Before callMethod exists, a consent call removes queued consent commands and moves the latest command to the queue head. This places a pre-loa…
Out of Scope Changes check ✅ Passed The source change is limited to Meta Pixel consent queue handling. The test changes validate the linked #928 behavior before and after load. No unrelated product behavior or unrelated files are change…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

📦 Package Size

⚠️ 3 size metrics grew

📚 22 runtime dependencies (no change)

Package output Gzipped Δ
@nuxt/scripts · dist/runtime 102 kB → 102 kB 🔴 +75 B (+0.1%)
@nuxt/scripts · published payload 219 kB → 219 kB 🔴 +75 B (+0.0%)
@nuxt/scripts · registry runtime 45 kB → 45 kB 🔴 +75 B (+0.2%)
All tracked output (25)
Package output Gzipped Raw
@nuxt/scripts-cli · runtime dependencies 72 kB 355 kB ✅
@nuxt/scripts-cli · dependency magicast 72 kB 355 kB ✅
@nuxt/scripts-cli · export . 3.4 kB 12 kB ✅
@nuxt/scripts-cli · published payload 3.4 kB 12 kB ✅
@nuxt/scripts · runtime dependencies 436 kB 1.92 MB ✅
@nuxt/scripts · dependency @nuxt/devtools-kit 2.9 kB 7.7 kB ✅
@nuxt/scripts · dependency @oxc-project/types 0 B 0 B ✅
@nuxt/scripts · dependency @vueuse/core 174 kB 707 kB ✅
@nuxt/scripts · dependency @vueuse/shared 39 kB 154 kB ✅
@nuxt/scripts · dependency h3 34 kB 146 kB ✅
@nuxt/scripts · dependency semver 25 kB 72 kB ✅
@nuxt/scripts · dependency sirv 8.8 kB 21 kB ✅
@nuxt/scripts · dependency unstorage 70 kB 225 kB ✅
@nuxt/scripts · dependency valibot 82 kB 590 kB ✅
@nuxt/scripts · dist/runtime 102 kB 300 kB 🔴
@nuxt/scripts · export . 26 kB 106 kB ✅
@nuxt/scripts · export ./registry 29 kB 91 kB ✅
@nuxt/scripts · export ./stats 13 kB 91 kB ✅
@nuxt/scripts · export ./types-source 48 kB 244 kB ✅
@nuxt/scripts · published payload 219 kB 832 kB 🔴
@nuxt/scripts · components runtime 2.5 kB 6.4 kB ✅
@nuxt/scripts · composables runtime 7.8 kB 26 kB ✅
@nuxt/scripts · registry runtime 45 kB 134 kB 🔴
@nuxt/scripts · server runtime 29 kB 87 kB ✅
@nuxt/scripts · utils runtime 2.9 kB 8.1 kB ✅
Runtime dependencies (22)
Package Dependency Requested Resolved Cost
@nuxt/scripts-cli magicast ^0.5.5 0.5.5 📦 72 kB gzip
@nuxt/scripts-cli pathe ^2.0.3 2.0.3 ♻️ free via Nuxt 4.5.2
@nuxt/scripts @nuxt/devtools-kit ^3.4.2 3.4.2 📦 2.9 kB gzip
@nuxt/scripts @oxc-project/types ^0.150.0 0.150.0 📦 0 B gzip
@nuxt/scripts @vueuse/core ^14.4.0 14.4.0 📦 174 kB gzip
@nuxt/scripts @vueuse/shared ^14.4.0 14.4.0 📦 39 kB gzip
@nuxt/scripts consola ^3.4.2 3.4.2 ♻️ free via Nuxt 4.5.2
@nuxt/scripts defu ^6.1.7 6.1.7 ♻️ free via Nuxt 4.5.2
@nuxt/scripts h3 ^1.15.11 1.15.11 📦 34 kB gzip
@nuxt/scripts magic-string ^1.4.1 1.4.1 ♻️ free via Nuxt 4.5.2
@nuxt/scripts ofetch ^1.5.1 1.5.1 ♻️ free via Nuxt 4.5.2
@nuxt/scripts ohash ^2.0.12 2.0.12 ♻️ free via Nuxt 4.5.2
@nuxt/scripts oxc-walker ^1.1.1 1.1.1 ♻️ free via Nuxt 4.5.2
@nuxt/scripts pathe ^2.0.3 2.0.3 ♻️ free via Nuxt 4.5.2
@nuxt/scripts semver ^7.8.5 7.8.5 📦 25 kB gzip
@nuxt/scripts sirv ^3.0.2 3.0.2 📦 8.8 kB gzip
@nuxt/scripts std-env ^4.2.0 4.2.0 ♻️ free via Nuxt 4.5.2
@nuxt/scripts ufo ^1.6.4 1.6.4 ♻️ free via Nuxt 4.5.2
@nuxt/scripts ultrahtml ^1.7.0 1.7.0 ♻️ free via Nuxt 4.5.2
@nuxt/scripts unplugin ^3.3.0 3.3.0 ♻️ free via Nuxt 4.5.2
@nuxt/scripts unstorage ^1.17.5 1.17.5 📦 70 kB gzip
@nuxt/scripts valibot ^1.5.0 1.5.0 📦 82 kB gzip

Baseline: main_@_4bb52cc4___2026-09-22 · gzip is the comparison metric · changes below 16 B gzip are ignored

@harlan-zw harlan-zw added harlan-agent-review Approve automated work for the current issue state or pull request head commit. harlan-agent-review-required Pull request triage requires an adversarial Review for this head commit. harlan-agent-running An Agent holds a Task on this issue or pull request right now. harlan-agent-blocked The automated Review found a material defect in this head commit. and removed harlan-agent-review Approve automated work for the current issue state or pull request head commit. harlan-agent-running An Agent holds a Task on this issue or pull request right now. harlan-agent-review-required Pull request triage requires an adversarial Review for this head commit. harlan-agent-blocked The automated Review found a material defect in this head commit. labels Sep 26, 2026
@harlan-zw
harlan-zw merged commit 9a631c9 into nuxt:main Sep 28, 2026
11 of 12 checks passed
@harlan-zw harlan-zw removed the harlan-agent-review-required Pull request triage requires an adversarial Review for this head commit. label Sep 28, 2026
@felixgabler

Copy link
Copy Markdown
Contributor Author

Thanks for merging this, @harlan-zw!

We're still on 1.3.9 in production and carry this fix as a local patch for now. Is a 1.x backport planned, like #897? If it helps, I'm happy to open a PR against the 1.x branch; the change applies there as is.

@harlan-zw

Copy link
Copy Markdown
Collaborator

No problem, thanks for the PR. I'll arrange that shortly :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Meta Pixel: consent.grant() before fbevents loads never takes effect with defaultConsent: 'denied'

2 participants