Skip to main content
Releases

Nuxt Scripts v1 is the project's first stable release. It adds a first-party proxy, per-script Partytown support, server-rendered social embeds, consent APIs, and new registry integrations.

Highlights

First-Party Mode

Loading a third-party script gives its provider browser data that it can use for fingerprinting.

The amount of data varies by provider. The Nuxt Scripts audit snapshot records 5 X Pixel cookies and requests to 3 domains, plus browser signals such as battery status, CPU count, screen data, timezone, language, platform, and touch capability. It records Clarity traffic across 3 domains.

First-party mode bundles supported scripts at build time and serves them from your domain. Its reverse proxy forwards supported runtime requests through your server and anonymizes fields such as IP addresses (180.233.124.74180.233.124.0) and browser versions (Mozilla/5.0 (compatible; Chrome/120.0)). Registry scripts use these capabilities by default when they declare support for them.

Serving bundled scripts from your origin avoids DNS and connection setup for the original script host. Same-origin proxy URLs are also less likely to match host-based blocking rules, although other blocking rules can still identify them. First-party mode does not remove consent requirements or the need for a consent banner where the law requires one.

See the First-Party Mode Guide and PR #577 for details.

Partytown Web Worker Support

Set partytown: true to run a supported registry script in a Partytown web worker. Its first-party bundling and proxy capabilities still apply. See PR #576.

The current Partytown quick path renders the script into the initial HTML and returns a loaded stub. It bypasses trigger resolution, use() proxies, load(), and reload(). In the configuration below, trigger enables generation of each global registry instance, but onNuxtReady does not delay the Partytown script.

Nuxt Scripts configures forwarding for googleAnalytics, plausibleAnalytics, cloudflareWebAnalytics, umamiAnalytics, matomoAnalytics, segment, mixpanelAnalytics, clarity, bingUet, metaPixel, xPixel, tiktokPixel, snapchatPixel, redditPixel, linkedinInsight, and calendly.

Do not assume that forwarding alone makes every registry integration usable on the current quick path. For example, Plausible and Umami need attributes that this path drops, while Clarity depends on a client initialization callback that never runs.

The Partytown tracker has an open report of dropped GA4 sessions when Google Tag Manager runs in a worker. Nuxt Scripts does not declare Partytown support for GTM. Test analytics delivery before moving GA4 to Partytown.

Server-Rendered Social Embeds

Twitter widgets, Instagram embeds, and Bluesky posts normally load vendor scripts in the browser. Following the Cloudflare Zaraz approach, Nuxt Scripts can fetch the embed data on the server and rewrite supported media URLs through your domain. See PR #590.

<ScriptXEmbed tweet-id="1754336034228171055">
  <template #default="{ userName, text, likesFormatted, photos }">
    <!-- Render the post with your own markup -->
  </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="{ displayName, text, images }">
    <article>
      <strong>{{ displayName }}</strong>
      <p>{{ text }}</p>
      <img v-for="image in images" :key="image.fullsize" :src="image.thumb" :alt="image.alt">
    </article>
  </template>
</ScriptBlueskyEmbed>

v1 adds two layers of consent control. See the Consent Guide, PR #544, PR #631, and PR #712.

Consent trigger: useScriptTriggerConsent() prevents a script from loading until consent is granted. Its reactive state records later revocation, although revoking consent does not unload a script:

const trigger = useScriptTriggerConsent()
useScriptGoogleTagManager({ id: 'GTM-XXX', scriptOptions: { trigger } })

trigger.accept() // Grant → script loads
trigger.revoke() // Set consented to false; does not unload an already-loaded script
trigger.consented // Ref<boolean>

Vendor controls: consent-aware registry scripts expose a consent object and a typed defaultConsent option that runs before the first tracking call. This covers Google Analytics, Google Tag Manager, Bing UET, Meta Pixel, TikTok Pixel, Matomo, Mixpanel, PostHog, and Clarity. The types preserve each vendor's vocabulary, including GCMv2 for Google and Bing, grant/revoke for Meta, and 'opt-in'/'opt-out' defaults for Mixpanel and PostHog. Import the GCMv2 ConsentState from #nuxt-scripts/types.

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()

DevTools

The Nuxt DevTools panel now covers the v1 privacy and capability model (implementation commit):

  • First-party panel: proxy routes, active anonymization flags, and upstream domains.
  • Registry panel: support and activation status for bundle, proxy, and partytown.
  • Script inspection: status, load timing, network waterfall, bundle size, and inline documentation.
  • Standalone view: a separate DevTools tab connected to the Nuxt development server.

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()

Subresource Integrity Hashes

Set assets.integrity to generate Subresource Integrity hashes for bundled scripts. See PR #575.

export default defineNuxtConfig({
  scripts: {
    assets: {
      integrity: 'sha384'
    }
  }
})

Script Stats Export

The new @nuxt/scripts/stats subpath exports script privacy and performance data for audits; the source lists its measured fields and rating inputs.

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

  • Isolated player instances (#586): Multiple players no longer share state
  • Aspect ratio control: New ratio prop
  • Unmount cleanup: Player instances are destroyed on unmount

Vimeo Player

  • Aspect ratio control (#624): New ratio prop, matching YouTube Player API

Google Maps

The Google Maps integration now exposes Vue components for markers, shapes, overlays, clustering, static maps, and GeoJSON.

Declarative components (#510): 11 components use Vue injection for parent-child communication and clean up on unmount.

Custom marker content (#658): The #content slot on ScriptGoogleMapsMarker replaces the default pin with HTML or a Vue template.

<ScriptGoogleMapsMarker :position="{ lat: -34.397, lng: 150.644 }">
  <template #content>
    <div class="price-tag">$420k</div>
  </template>
</ScriptGoogleMapsMarker>

Custom overlay view (#658): ScriptGoogleMapsOverlayView renders Vue content at a map position. Inside a marker, it inherits the position and follows the marker while dragging. Use v-model:open to toggle it 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 accept :position without an options object.

Additional components:

  • ScriptGoogleMapsStaticMap (#673): The static placeholder is now a standalone component. By default, images are routed through your server, which injects the API key into the upstream request. Google's current terms restrict storing and serving Static Maps images from an application server; the billing guide explains how to bypass this proxy with an explicit api-key.
  • ScriptGoogleMapsGeoJson (#656): Declarative wrapper around google.maps.Data for loading and styling GeoJSON with full event bindings.

Infrastructure:

  • Color mode support (#587): Auto light/dark map switching with mapIds prop
  • Geocode proxy: Server-side geocoding hides API keys and caches results. Review the current caching restriction in the billing guide before using it.
  • Resource cleanup (#651): useGoogleMapsResource cleans up subcomponents on unmount, including across async boundaries
  • Marker clustering (#517, #653): Batch operations use noDraw to avoid repeated renders

Deprecation: v1 consolidates the legacy ScriptGoogleMapsMarker (wrapping google.maps.Marker) and ScriptGoogleMapsAdvancedMarkerElement names into ScriptGoogleMapsMarker (wrapping google.maps.marker.AdvancedMarkerElement). v1 removes ScriptGoogleMapsPinElement; a slot-passthrough compatibility shim remains, but custom marker markup belongs in the #content slot on ScriptGoogleMapsMarker.

Environment-Variable Config

The module now auto-populates runtimeConfig.public.scripts for fields that each registry integration declares as environment-backed. IDs, keys, and domains covered by those declarations resolve from NUXT_PUBLIC_SCRIPTS_* env vars without matching runtimeConfig boilerplate. See PR #634.

# .env
NUXT_PUBLIC_SCRIPTS_GOOGLE_ANALYTICS_ID=G-XXXXXX
NUXT_PUBLIC_SCRIPTS_POSTHOG_API_KEY=phc_xxx

Breaking Changes and 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.

Bug Fixes

  • cdfb697 fix(rybbit): queue custom events before script loads (#585)
  • f8ce5a1 fix(gtm): invoke onBeforeGtmStart callback when ID is in config (#584)
  • a8d20b0 fix: add estree-walker as a dependency (#583)
  • 4c79486 fix(plausible): use consistent window reference in clientInit stub (#574)
  • 78367b1 fix(matomo): respect user-provided URL protocol (#572)
  • c685f43 fix: broken type augmenting
  • e2050a2 fix: align templates with existing augments (#589)
  • da3a8cc chore: include .nuxt types (#588)
  • 039380e fix: prevent memory leaks in all Google Maps sub-components (#651)
  • 7e139b3 fix: avoid mutating runtimeConfig scriptOptions (#638)
  • 01b1af4 fix: expand self-closing <Script*> tags to prevent SFC extraction issues (#613)
  • c3a6098 fix: preserve compressed/binary request bodies in proxy handler (#619)
  • 96db067 fix: missing Bing UET types (#710)
  • fdaf089 fix(types): prevent registry entry types from collapsing to never (#701)
  • 698a585 fix: inherit registry scriptOptions in composable instances (#691)
  • 506dfd8 fix(google-maps): guard pan-on-open for closed/unpositioned overlay (#698)
  • 6fdd533 fix(google-maps): prevent center reset on re-render and export clusterer types (#686)
  • 0e4ae9e fix(google-maps): prevent zoom/pan reset when overlay toggles (#685)
  • 33ebf61 fix(google-maps): close races in resolveQueryToLatLng (#693)
  • 4df13ed fix: add defineSlots to all components for proper slot type inference (#684)
  • afbb6bd fix(types): broken IDE display of registry types (#683)
  • 63d4da5 fix: add v0 migration warnings and docs for breaking config changes (#679)
  • 3007458 fix(google-analytics): add www.google.com and www.googletagmanager.com to proxy domains (#678)
  • 1c47e72 fix: add missing proxy domains across registry scripts
  • e6ecfff fix(google-maps): bind $attrs to overlay view (#672)
  • c2f8a8b fix(google-maps): remove redundant slot props from OverlayView (#666)
  • b65e5db fix(google-maps): OverlayView, InfoWindow, and AdvancedMarkerElement DX issues (#660)
  • a597de9 fix: prevent memory leak in ScriptGoogleMapsAdvancedMarkerElement (#649)
  • 32ff4fa fix: improve registry script DX and type safety (#647)
  • 569eeeb fix(first-party): inject proxy endpoints for boolean/mock registry entries (#640)
  • 00fbaae fix: allow custom script keys in ScriptRegistry type (#632)
  • 3b93696 fix(plausible): broken firstParty mode
  • 1c31a71 fix(gravatar): broken proxy