Nuxt Scripts v1 is the first stable release.
Nuxt Scripts v1 is the first stable release, pushing the ecosystem forward for better privacy and performance for third-party scripts.
📣 Highlights
🔒 First-Party Mode: Privacy Focused Proxy
Every third-party script request exposes your users data to fingerprinting.
Different providers are more intrusive, for example, the X Pixel accesses 9 browser fingerprinting APIs (including navigator.getBattery()), sets 5 tracking cookies, and makes requests to 3 separate domains. Microsoft Clarity reads 10 fingerprinting APIs across 3 domains.
First-party mode acts as a reverse proxy: scripts are bundled at build time and served from your domain, while runtime requests are securely forwarded through your server. Data sent to third-party servers gets anonymised: IPs (180.233.124.74 -> 180.233.124.0), browser versions (Mozilla/5.0 (compatible; Chrome/120.0)) and more. This is auto-enabled for all scripts that support it.
A side-effect is a performance boost from avoiding extra DNS lookups, fewer cookie banners, and reducing expensive fingerprinting queries. It also makes ad-blockers ineffective since requests appear same-origin.
See the First-Party Mode Guide and PR #577 for details.
🛠️ Rebuilt DevTools
The Nuxt DevTools panel has been rewritten around the v1 privacy and capability model. New views surface the things v1 does differently.
🎉 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. Integrates directly with first-party mode. See PR #576.
Set partytown: true per-script:
export default defineNuxtConfig({
modules: ['@nuxtjs/partytown', '@nuxt/scripts'],
scripts: {
registry: {
plausibleAnalytics: { domain: 'example.com', partytown: true },
fathomAnalytics: { site: 'XXXXX', partytown: true },
umamiAnalytics: { websiteId: 'xxx', partytown: true },
}
}
// Forward array auto-configured per-script!
})Auto-forwarding supported for: googleAnalytics, plausibleAnalytics, fathomAnalytics, umamiAnalytics, matomoAnalytics, segment, mixpanelAnalytics, bingUet, metaPixel, xPixel, tiktokPixel, snapchatPixel, redditPixel, cloudflareWebAnalytics
⚠️ 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, Bluesky posts) hurt performance and leak user data. Following the Cloudflare Zaraz approach, Nuxt Scripts now fetches embed data server-side and securely proxies 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>
<ScriptBlueskyEmbed post-url="https://bsky.app/profile/...">
<template #default="{ html }">
<div v-html="html" />
</template>
</ScriptBlueskyEmbed>✋ First-Class Consent Controls
v1 treats consent as a first-class concern with two complementary APIs. See the Consent Guide, PR #544, PR #631, and PR #712.
Every consent-aware registry script now exposes a vendor-native consent object on the returned instance plus a typed defaultConsent option applied before the first tracking call.
const gtm = useScriptGoogleTagManager({
id: 'GTM-XXX',
defaultConsent: { ad_storage: 'denied', analytics_storage: 'denied' },
})
// Later, after the user accepts
gtm.consent.update({ ad_storage: 'granted', analytics_storage: 'granted' })
const ttq = useScriptTikTokPixel({ id: '...', defaultConsent: 'hold' })
ttq.consent.grant() // or .revoke() / .hold()
const meta = useScriptMetaPixel({ id: '...', defaultConsent: 'denied' })
meta.consent.grant()📦 New Registry Scripts
- PostHog Analytics (#568): Product analytics with feature flags
- Google reCAPTCHA v3 (#567): Invisible bot protection
- TikTok Pixel (#569): Conversion tracking
- Google Sign-In (#573): One-tap authentication
- Rybbit Analytics (#453): Privacy-focused open source analytics
- Databuddy Analytics (#495): Lightweight analytics
- Bing UET (#650): Microsoft Advertising conversion tracking
- Mixpanel Analytics (#648): Product analytics and user tracking
- Vercel Analytics (#605): Vercel Web Analytics integration
- Gravatar (#606): Avatar service with privacy-preserving proxy
Other Changes
🔄 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'
}
}
})📊 Script Stats Export
New @nuxt/scripts/stats subpath export for auditing script privacy, performance, and security characteristics.
import { getScriptStats } from '@nuxt/scripts/stats'
const stats = await getScriptStats()
// Privacy ratings (A+ to F), performance ratings, CWV estimates,
// cookie analysis, network behavior, tracked data types🎬 YouTube Player Overhaul
- Isolated player instances (#586): Multiple players work correctly
- Aspect ratio control: New
ratioprop - Proper cleanup: Players destroyed on unmount
📹 Vimeo Player Enhancements
- Aspect ratio control (#624): New
ratioprop, matching YouTube Player API
🗺️ Google Maps Overhaul
The Google Maps integration received a major DX overhaul for v1, making it feel like a native Vue component library rather than a wrapper around options bags.
Declarative SFC Components (#510): 11 composable components for markers, shapes, overlays, clustering, and more. All use Vue's injection system for parent/child communication and clean up automatically on unmount.
Custom Marker Content (#658): The #content slot on ScriptGoogleMapsMarker replaces the default pin with any HTML or Vue template. Build price tags, status badges, or any custom marker visual declaratively.
<ScriptGoogleMapsMarker :position="{ lat: -34.397, lng: 150.644 }">
<template #content>
<div class="price-tag">$420k</div>
</template>
</ScriptGoogleMapsMarker>Custom Overlay View (#658): ScriptGoogleMapsOverlayView renders arbitrary Vue content at a map position with full styling control. When nested inside a marker, it auto-inherits position and follows the marker during drag. Supports v-model:open for toggling visibility without remounting.
<ScriptGoogleMapsMarker :position="pos" @click="open = !open">
<ScriptGoogleMapsOverlayView v-model:open="open" anchor="bottom-center" :offset="{ x: 0, y: -50 }">
<MyCustomPopup @close="open = false" />
</ScriptGoogleMapsOverlayView>
</ScriptGoogleMapsMarker>Direct :position Prop: Marker components now accept :position as a top-level prop (no options bag needed for the most common case).
Additional Components:
ScriptGoogleMapsStaticMap(#673): The static placeholder is now a standalone component, with images routed through your server so API keys stay server-side. Use it inside#placeholderonScriptGoogleMaps, or standalone for store locators and contact pages that never need the interactive Maps API.ScriptGoogleMapsGeoJson(#656): Declarative wrapper aroundgoogle.maps.Datafor loading and styling GeoJSON with full event bindings.
Infrastructure:
- Color mode support (#587): Auto light/dark map switching with
mapIdsprop - Geocode proxy: Server-side geocoding reduces billing and hides API keys
- Memory leak fixes (#651):
useGoogleMapsResourcecomposable ensures all sub-components clean up safely on unmount, even across async boundaries - Marker clustering perf (#517, #653): Batch operations with
noDrawflag to avoid multiple rerenders
Deprecation: The legacy ScriptGoogleMapsMarker (wrapping google.maps.Marker) and ScriptGoogleMapsAdvancedMarkerElement names have been consolidated into ScriptGoogleMapsMarker (wrapping google.maps.marker.AdvancedMarkerElement). We removed ScriptGoogleMapsPinElement; use the #content slot on ScriptGoogleMapsMarker instead.
🔧 Environment-Variable Config
The module now auto-populates runtimeConfig.public.scripts defaults for any enabled registry entry. Script IDs, keys, and domains resolve from NUXT_PUBLIC_SCRIPTS_* env vars without any runtimeConfig boilerplate. See PR #634.
# .env
NUXT_PUBLIC_SCRIPTS_GOOGLE_ANALYTICS_ID=G-XXXXXX
NUXT_PUBLIC_SCRIPTS_POSTHOG_API_KEY=phc_xxx⚠️ Breaking Changes & Migration
Upgrading from v0? See the v0 to v1 migration guide for the summary table and before/after diffs for every breaking change and deprecation.
Changelog
🚨 Breaking Changes
- First party mode config - by @harlan-zw (01ae8)
- Config consolidation for v1 - by @harlan-zw in #661 (8deac)
- Simplify Google Maps components - by @harlan-zw (d381c)
- Extract
ScriptGoogleMapsStaticMapas standalone component - by @harlan-zw in #673 (6947c) - google-maps:
- Deprecate top-level center/zoom props - by @harlan-zw in #694 (bf560)
- Rename googleMaps expose to mapsApi - by @harlan-zw in #695 (966de)
- OverlayView class extraction and reactive position rendering - by @harlan-zw in #697 (c3347)
- paypal:
- Migrate to PayPal JavaScript SDK v6 - by @harlan-zw in #628 (89e33)
🚀 Features
- Script
.reload()- by @harlan-zw (77f85) - Add SSR social media embeds for X and Instagram - by @harlan-zw and Claude Opus 4.6 (1M context) in #590 (aa542)
- Experimental nuxt/partytown support - by @harlan-zw and Claude Opus 4.6 (1M context) in #576 (b67c9)
- First-party proxy mode with privacy anonymization - by @harlan-zw, Claude Opus 4.6 (1M context) and Copilot Autofix powered by AI in #577 (3bc81)
@nuxt/scripts/statssubpath export - by @harlan-zw (202a8)/types-sourcesubpath export for doc gen - by @harlan-zw (e415b)- Add Vercel Analytics support - by @harlan-zw in #605 (2a38f)
- Add Gravatar integration with privacy-preserving proxy - by @harlan-zw in #606 (9576b)
- Auto-populate runtimeConfig for .env registry script overrides - by @harlan-zw in #634 (1db6f)
- Bluesky embed - by @harlan-zw (491da)
- Endpoint opt-in, path standardization, proxy consolidation - by @harlan-zw in #644 (fd14d)
- Add Mixpanel analytics registry script - by @harlan-zw in #648 (d11be)
- Consent trigger revocation support - by @harlan-zw in #631 (a6401)
- Add Bing UET (Microsoft Advertising) registry script - by @harlan-zw in #650 (696af)
- Integrate Partytown with first-party proxy mode - by @harlan-zw in #654 (80518)
- Add
ScriptGoogleMapsGeoJsoncomponent - by @harlan-zw in #655 (ee65e) - Add
ScriptGoogleMapsGeoJsoncomponent " - by @harlan-zw in #655 (28f80) - New devtools - by @harlan-zw (1c285)
- Vendor-native consent controls for consent-aware scripts - by @harlan-zw in #712 (04659)
- ScriptVimeoPlayer:
- bundling:
- Add automatic SRI integrity hash generation - by @harlan-zw and Claude Opus 4.6 (1M context) in #575 (fbdf9)
- first-party:
- Exclude fingerprinting scripts, fix per-script opt-out - by @harlan-zw in #662 (1ac35)
- google-maps:
- Add ScriptGoogleMapsGeoJson component - by @harlan-zw and @DamianGlowala in #656 (fb549)
- DX overhaul for v1 - by @harlan-zw in #659 (5a8e6)
- Overlay view panning, cluster auto-hide, and render guard - by @harlan-zw in #663 (7fc0b)
- Support transitions with
data-state- by @harlan-zw (61319) - Add #renderer slot to ScriptGoogleMapsMarkerClusterer - by @harlan-zw in #675 (46798)
- OverlayView defaultOpen prop and LatLng position widening - by @harlan-zw in #696 (7bfc7)
- posthog:
- Support proxy mode - by @harlan-zw (6c467)
- proxy:
- Granular per-script privacy controls - by @harlan-zw in #611 (ec2a6)
- registry:
- Add TikTok Pixel script - by @harlan-zw and Claude Opus 4.6 (1M context) in #569 (48385)
- Add Google reCAPTCHA v3 script - by @harlan-zw and Claude Opus 4.6 (1M context) in #567 (c2601)
- Add PostHog analytics script - by @harlan-zw and Claude Opus 4.6 (1M context) in #568 (c91ea)
- Add Google Sign-In script - by @harlan-zw and Claude Opus 4.6 (1M context) in #573 (3b4e6)
- security:
- HMAC signing infrastructure for proxy endpoints - by @harlan-zw in #699 (3ca07)
🐞 Bug Fixes
- Broken type augmenting - by @harlan-zw (c685f)
- Add
estree-walkeras a dependency - by @danielroe in #583 (a8d20) - Align templates with existing augments - by @danielroe and @harlan-zw in #589 (e2050)
- Safer resolve of triggers via nuxt.config - by @harlan-zw (73870)
- Import from
@nuxt/schema- by @danielroe in #600 (1addd) - Explicit opt-in for proxy mode - by @harlan-zw (ef5f4)
- Migrate to unplugin v3 - by @harlan-zw (409a8)
- Better registry key matching - by @harlan-zw (23c75)
- Broken bare domain path matching - by @harlan-zw (58fe9)
- Broken bundle transforms - by @harlan-zw (84709)
- Protect against broken new URL when proxying - by @harlan-zw (cb7ff)
- Preserve compressed/binary request bodies in proxy handler - by @harlan-zw in #619 (c3a60)
- Npm-mode registry scripts stored at $$scripts instead of $scripts - by @zizzfizzix in #623 (3163b)
- Broken $script write - by @harlan-zw (985ab)
- Allow custom script keys in ScriptRegistry type - by @harlan-zw in #632 (00fba)
- First-party mode improvements - by @harlan-zw (93dee)
- Improved script types - by @harlan-zw (b3439)
- Flakey first-party mode - by @harlan-zw (75485)
- Avoid mutating runtimeConfig scriptOptions - by @onmax in #638 (7e139)
- Broken schema generation - by @harlan-zw (0f047)
- Bad first party warnings - by @harlan-zw (8877c)
- Target canvas fingerprinting at build-time - by @harlan-zw (b1c23)
- Improve registry script DX and type safety - by @harlan-zw in #647 (32ff4)
- Resolve merge conflicts keeping normalized tuple approach with false support - by @harlan-zw (3db19)
- Add BuiltInRegistryScriptKey to prevent augmented keys from breaking typecheck - by @harlan-zw (40056)
- Prevent memory leak in ScriptGoogleMapsAdvancedMarkerElement - by @harlan-zw in #649 (a597d)
- Prevent memory leaks in all Google Maps sub-components - by @harlan-zw in #651 (03938)
- Update e2e bundle snapshot hash - by @harlan-zw (8aaea)
- Env not being picked up always - by @harlan-zw (8a938)
- Mark useScript instance as raw - by @harlan-zw (37d38)
- Asset path broken when using query params - by @harlan-zw (710f8)
- Remove redundant
=== falsecheck causing type error in registry - by @harlan-zw (f53a1) - Add missing proxy domains across registry scripts - by @harlan-zw (1c47e)
- Add v0 migration warnings and docs for breaking config changes - by @harlan-zw in #679 (63d4d)
- Add defineSlots to all components for proper slot type inference - by @harlan-zw in #684 (4df13)
- Inherit registry scriptOptions in composable instances - by @harlan-zw in #691 (698a5)
- Missing Bing UET types - by @harlan-zw in #710 (96db0)
- Quiter warnings - by @harlan-zw (c98e8)
- Runtime script proxy signing - by @harlan-zw (6725e)
- Quite warnings for embeds - by @harlan-zw (230cd)
- ScriptGoogleMapsPinElement:
- V1 migration helpers - by @harlan-zw (a1595)
- Vimeo:
placeholderObjectFit- by @harlan-zw (61b1c)
- YouTube:
- Fetch placeholder with high priority if above the folder - by @harlan-zw (420fe)
- ci:
- Run nuxt prepare at root so .nuxt/tsconfig.json exists for build - by @harlan-zw (edc3b)
- devtools:
- Clean up - by @harlan-zw (1178c)
- Broken tooltips - by @harlan-zw (ae2f2)
- first-party:
- Inject proxy endpoints for boolean/mock registry entries - by @oritwoen in #640 (569ee)
- Missing scripts - by @harlan-zw (2f0c9)
- ga:
- Broken script rewrite - by @harlan-zw (e0e1c)
- google-analytics:
- Add www.google.com and www.googletagmanager.com to proxy domains - by @harlan-zw in #678 (30074)
- google-maps:
- Static maps proxy, color mode, and bug fixes - by @harlan-zw and Claude Opus 4.6 (1M context) in #587 (2f8ad)
- Use noDraw flag in AdvancedMarkerElement clusterer operations - by @harlan-zw in #653 (d2591)
- Fix OverlayView, InfoWindow, and AdvancedMarkerElement DX issues - by @harlan-zw in #660 (b65e5)
- Proxy registration order - by @harlan-zw (9e9f6)
- Flatten emits - by @harlan-zw (38697)
- Maybe solve race condition and warnings - by @harlan-zw (72484)
- Remove redundant slot props from OverlayView - by @harlan-zw in #666 (c2f8a)
- Bind
$attrsto overlay view - by @DamianGlowala and Damian Głowala in #672 (e6ecf) - Prevent zoom/pan reset when overlay toggles - by @harlan-zw in #685 (0e4ae)
- Prevent center reset on re-render and export clusterer types - by @harlan-zw and Claude Opus 4.6 (1M context) in #686 (6fdd5)
- Close races in resolveQueryToLatLng - by @harlan-zw in #693 (33ebf)
- Guard pan-on-open for closed/unpositioned overlay - by @harlan-zw in #698 (506df)
- gravatar:
- Broken proxy - by @harlan-zw (1c31a)
- gtm:
- instagram:
- Safer HTML parsing - by @harlan-zw (e4b22)
- matomo:
- Respect user-provided URL protocol instead of forcing HTTPS - by @harlan-zw in #572 (78367)
- plausible:
- Use consistent window reference in clientInit stub - by @harlan-zw and Claude Opus 4.6 (1M context) in #574 (4c794)
- Broken firstParty mode - by @harlan-zw (3b936)
- Support bundling with scriptId - by @harlan-zw (9dcf6)
- posthog:
- 'history_change' as a capture_pageview option - by @zizzfizzix in #620 (f0e11)
- Unwrap array registry entry before injecting firstParty apiHost - by @zizzfizzix in #625 (86945)
- Expose Partial on config field - by @zizzfizzix in #626 (52f01)
- Ensure api host is runtime properly - by @harlan-zw (f0472)
- proxy:
- Missing path separators - by @harlan-zw (a935e)
- Missing script src - by @harlan-zw (fadda)
- rybbit:
- Queue custom events before script loads - by @harlan-zw and Claude Opus 4.6 (1M context) in #585 (cdfb6)
- Deprecate window accessor - by @harlan-zw (05dfc)
- script-meta:
- Better stats - by @harlan-zw (722ea)
- stats:
- Expose all privacy apis - by @harlan-zw (a5fdf)
- tiktok:
- Missing global - by @harlan-zw (8b391)
- types:
- Add googleSignIn to ScriptRegistry - by @zizzfizzix in #627 (be31e)
- Broken IDE display of registry types - by @harlan-zw and Copilot in #683 (afbb6)
- Prevent registry entry types from collapsing to
never- by @harlan-zw in #701 (fdaf0)
- youtube:
- Isolate player instances and fix multiple bugs - by @harlan-zw and Claude Opus 4.6 (1M context) in #586 (dc4c7)
🏎 Performance
- Migrate plugins to oxc-walker (parseAndWalk) - by @harlan-zw in #610 (abb95)