-
Notifications
You must be signed in to change notification settings - Fork 75
Description
Nuxt Scripts v1 is the first stable release.
Nuxt Scripts v1 is all about privacy and performance — route analytics through your own domain, move scripts off the main thread, and render social embeds server-side without loading third-party JavaScript.
📣 Highlights
🔒 First-Party Mode
Third-party scripts expose data that can be used for fingerprinting users accross sites. Every request shares the user's IP address, and scripts can set third-party cookies for cross-site tracking. Ad blockers rightfully block these for privacy reasons.
First-party mode routes all script traffic through your own domain.
See PR #577.
export default defineNuxtConfig({
scripts: {
firstParty: true,
registry: {
googleAnalytics: { id: 'G-XXXXXX' },
metaPixel: { id: '123456' },
}
}
})What happens:
- Scripts downloaded at build time and served from your domain
- Collection URLs rewritten to local paths (
/_scripts/c/ga) - Nitro route rules proxy requests to original endpoints
- User IPs stay private: third parties see your server's IP, not your users'
- No third-party cookies: requests are same-origin
- Works with ad blockers: requests appear first-party
Supported: Google Analytics, GTM, Meta Pixel, TikTok, Segment, Clarity, Hotjar, X/Twitter, Snapchat, Reddit.
⚡ Partytown Web Worker Support
Load third-party scripts off the main thread using Partytown. Scripts run in a web worker, freeing the main thread for your app.
See PR #576.
export default defineNuxtConfig({
modules: ['@nuxtjs/partytown', '@nuxt/scripts'],
scripts: {
partytown: ['plausible', 'fathom', 'umami'],
registry: {
plausible: { domain: 'example.com' },
fathom: { site: 'XXXXX' }
}
}
// Forward array auto-configured — no manual setup needed!
})Auto-forwarding supported for: googleAnalytics, plausible, fathom, umami, matomo, segment, metaPixel, xPixel, tiktokPixel, snapchatPixel, redditPixel, cloudflareWebAnalytics
⚠️ Note: GA4 has known issues with Partytown. GTM is not compatible (requires DOM access). Consider Plausible, Fathom, or Umami instead.
🐦 SSR Social Embeds
Third-party embed scripts (Twitter widgets, Instagram embeds) hurt performance and leak user data. Following the Cloudflare Zaraz approach, we now fetch embed data server-side and proxy all assets through your domain.
See PR #590.
<ScriptXEmbed tweet-id="1754336034228171055">
<template #default="{ userName, text, likesFormatted, photos }">
<!-- Full styling control via scoped slots -->
</template>
</ScriptXEmbed>
<ScriptInstagramEmbed post-url="https://instagram.com/p/ABC123/">
<template #default="{ html, shortcode }">
<div v-html="html" />
</template>
</ScriptInstagramEmbed>Privacy benefits:
- Zero third-party JavaScript loaded
- No cookies set by X/Instagram
- User IPs not shared with third parties
- All content served from your domain
🔄 Script Reload API
Scripts now expose a .reload() method for re-executing DOM-scanning scripts after SPA navigation.
See commit 77f853b.
const script = useScript('/third-party.js')
await script.reload()🔐 Automatic SRI Integrity Hashes
Bundled scripts can automatically generate Subresource Integrity hashes.
See PR #575.
export default defineNuxtConfig({
scripts: {
assets: {
integrity: 'sha384'
}
}
})📦 New Registry Scripts
- PostHog Analytics (PR #568) — Product analytics with feature flags
- Google reCAPTCHA v3 (PR #567) — Invisible bot protection
- TikTok Pixel (PR #569) — Conversion tracking
- Google Sign-In (PR #573) — One-tap authentication
🎬 YouTube Player Overhaul
- Isolated player instances (PR #586) — Multiple players work correctly
- Aspect ratio control — New
ratioprop - Proper cleanup — Players destroyed on unmount
🗺️ Google Maps Enhancements
- Color mode support (PR #587) — Auto light/dark switching
- Static maps proxy — Hide API keys, fix CORS
🏷️ GTM Consent Mode
export default defineNuxtConfig({
scripts: {
registry: {
googleTagManager: {
id: 'GTM-XXXX',
defaultConsent: {
ad_storage: 'denied',
analytics_storage: 'denied'
}
}
}
}
})See PR #544.
⚠️ Breaking Changes
YouTube Player
Aspect Ratio: Now controlled via ratio prop instead of width/height.
<ScriptYouTubePlayer
video-id="..."
- :width="1280"
- :height="720"
+ ratio="16/9"
/>Placeholder Image: Default object-fit changed from contain to cover. Use placeholder-object-fit="contain" for old behavior.
Google Tag Manager
onBeforeGtmStart Callback: Now fires for cached/pre-initialized scripts. Guard if needed:
let initialized = false
useScriptGoogleTagManager({
onBeforeGtmStart: (gtag) => {
if (initialized) return
initialized = true
}
})🐛 Bug Fixes
cdfb697fix(rybbit): queue custom events before script loads (#585)f8ce5a1fix(gtm): invoke onBeforeGtmStart callback when ID is in config (#584)a8d20b0fix: addestree-walkeras a dependency (#583)4c79486fix(plausible): use consistent window reference in clientInit stub (#574)78367b1fix(matomo): respect user-provided URL protocol (#572)c685f43fix: broken type augmentinge2050a2fix: align templates with existing augments (#589)da3a8ccchore: include.nuxttypes (#588)
📖 Migration Guide
Full migration guide: https://scripts.nuxt.com/docs/guides/v1-migration
Breaking Changes by Impact
Medium Impact:
- YouTube Player:
ratioprop replaces width/height aspect calculation - YouTube Player: Placeholder
object-fitdefault changed tocover
Low Impact:
- GTM:
onBeforeGtmStartcallback timing changed - Type templates reorganized (run
nuxi prepare)