nuxt/scripts/nuxt-scripts
- community
Checking that the SKILL.md file is still in the repository.
Loads and controls third-party scripts in Nuxt with @nuxt/scripts v2, covering the scripts.registry config key, useScript, registry composables such as useScriptGoogleAnalytics and useScriptMetaPixel, consent triggers, bundling, and the first-party proxy. Use when adding analytics, pixels, or chat scripts to Nuxt, upgrading @nuxt/scripts from v1 to v2, or when a script never loads, loads before consent, or fails the build while downloading.
Install
npx vskill@latest install nuxt/scripts/nuxt-scriptsSKILL.md
@nuxt/scripts
Tested against @nuxt/scripts 2.0.0-beta.14 (npm beta) with Nuxt 4.6.0. v2 needs Nuxt ^4.6.0 || ^5.0.0, @unhead/vue and unhead ^3.4.2, and Node.js ^22.22.3 || ^24.15.0 || >=26.0.0. Composables and components are auto-imported. The examples import from #imports only to stay complete modules. Paths assume the Nuxt 4 app/ source directory.
Setup
Install with npx nuxi module add @nuxt/scripts@2.0.0-beta.14. It also adds the unhead and @unhead/vue peers. Keep the version: without it, nuxi installs the npm latest tag, which can be another major.
A registry entry is a flat object, 'mock', or false; any other shape throws. Its trigger decides whether it loads globally:
scripts.registry entry | Global script | Composable called with no options | |
|---|---|---|---|
{ id, trigger: 'onNuxtReady' } | loads on every page | returns the global instance | |
{ id } or {} | none | loads with the default onNuxtReady trigger | |
{ id, trigger: false } | none | never loads: it inherits trigger: false | |
'mock' | none | stays awaitingLoad; proxy calls do nothing |
Each registry key reads NUXT_PUBLIC_SCRIPTS_<KEY>_<FIELD> (camelCase key and field in SCREAMING_SNAKE_CASE) without a runtimeConfig declaration. The key must be in scripts.registry; otherwise the module warns and ignores the variable. These values are public.
Automatic behaviour
- SSR HTML contains no script tags. Scripts load on the client after hydration (
onNuxtReady). - SSR adds
<link rel="preload" fetchpriority="low">foronNuxtReadyandclienttriggers.warmupStrategy: falsestops it foronNuxtReady; aclienttrigger always preloads. - Cross-origin tags get
crossorigin="anonymous"andreferrerpolicy="no-referrer". - Registry scripts that support bundling are downloaded at build and served from
/_scripts/assets/<hash>.js. Setbundle: falseon an entry to load from the vendor. For most scripts this also stops the proxy, because the proxy rewrites the bundle. - Collection requests of supported scripts go through
/_scripts/p/<host>/.... Each script has a privacy tier, and every tier anonymises the IP. Setproxy: falseon an entry to send them direct. - Calls with the same
key, elsesrc, share one script. A second call returns the shared instance and ignores its input,use, andresolve. Itstriggerstill runs, and a call with no trigger usesonNuxtReady. - Each call gets its own consumer scope. Unmounting the component releases that call's callbacks and triggers; the shared script stays.
Common tasks
Load consent-gated scripts. A module-level trigger in app/utils/ is shared by every component:
Pass scriptOptions: { trigger: scriptsConsent } to every call of a consent-gated script, such as a component that tracks an event. One call without it loads the script before consent. scriptsConsent.revoke() sets consented to false but does not unload a loaded script. Call the vendor API through consent instead.
Call a vendor API. Proxy calls queue until load and return undefined; use onLoaded for a return value:
If the SDK signals readiness through a callback, use resolve({ waitFor }). load() then resolves only when the callback fires. The returned cleanup runs when the callback fires, or earlier if the script lifecycle ends:
Give each instance a unique key to load one script twice with different options.
Integrations
partytown: trueneeds@nuxtjs/partytown. It writes<script type="text/partytown" src>into SSR HTML at once. It ignorestrigger, so consent does not gate it. It keeps onlysrc, so other attributes are dropped.<ScriptXEmbed>,<ScriptInstagramEmbed>, and<ScriptBlueskyEmbed>needscripts.registry.xEmbed: {}(or the matching key). Without it, SSR fails with "requiresscripts.registry.instagramEmbedto be enabled". Embed routes are unsigned public proxies.- The DevTools panel needs
@nuxt/scripts-devtoolsat the same version. If npm has no matching version, skip the panel; loading and proxies work without it.
Traps
- The "config provided without a
trigger" warning offerstrigger: falsefor infrastructure only. That value also blocks every composable call without a trigger. Use{ id }with no trigger key, or passscriptOptions: { trigger }at the call. - A registry entry with a
triggerloads before consent code runs. A later call with a consent trigger gets that loaded instance. Keep consent-gated entries trigger-free. remove()removes the shared script for every consumer. To release one component's use, calldispose(), or let unmount do it.- In
scripts.globals, puttriggerin the tuple's second item:[{ src }, { trigger: { interaction: ['click'] } }]. Besidesrcit is ignored, and the script loads ononNuxtReady.'manual'holds the script at runtime but failsnuxt typecheck. - Option validation runs only in dev, and not for bundled scripts. When it runs, it holds the script and logs to the browser console, not the terminal. Production loads invalid options.
- The missing-trigger warning fires only for fields with no environment variable.
googleAnalytics: { id }gets no warning.
Deploy
- Bundling fetches each vendor script during
nuxt build. One failed download fails the build, such as a blocked host or an offline CI. Setassets.fallbackOnSrcOnBundleFail: trueto load that script from its vendor instead. - If
plausibleAnalyticshas a trigger or a composable call and noscriptId, the build fails with "plausibleAnalytics requires scriptId". A placeholder ID fails the download. - Bundles are cached for 7 days in
node_modules/.cache/nuxt/scripts. If a vendor script is stale, delete that folder. nuxt generate,nitro.static, and static presets disable the proxy with a build warning. Requests go direct and are not anonymised.
Upgrade from v1
Run npx @nuxt/scripts-cli@2.0.0-beta.14 migrate v2 --dry-run, then the same command without --dry-run. For what it misses and every v1 call with its v2 replacement, read references/migrate-v1.md.
Config
Reference: <https://scripts.nuxt.com/docs/api/nuxt-config>. Options that change behaviour:
defaultScriptOptions: default{ trigger: 'onNuxtReady' }, inherited by every script.privacy:true,false, or per-flag (ip,userAgent,language,screen,timezone,hardware) for proxied traffic.
Debug
- Read the returned
statusref:awaitingLoad,loading,loaded,error, orremoved.awaitingLoadmeans the trigger never fired. - Set
scripts.debug: trueto log each script'sregistered,loading, andloadedsteps in the browser console. - A
/_scripts/p/403 withDomain not allowedmeans the host is not a configured script domain.Local network targets are not allowedmeans the server's DNS resolves the vendor to a local address, such as an ad-blocking resolver.
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingpackages/script/skills/nuxt-scripts/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/nuxt/scripts/nuxt-scripts)