Guides

v1 Migration Guide

Last updated by Harlan Wilton in chore: lint.

What's New in v1

v1 focuses on privacy and performance: route analytics through your own domain, move scripts off the main thread, and render social embeds server-side.

First-Party Mode

Route all script traffic through your own domain for privacy and ad-blocker compatibility.

export default defineNuxtConfig({
  scripts: {
    firstParty: true,
    registry: {
      googleAnalytics: { id: 'G-XXXXXX' },
      metaPixel: { id: '123456' },
    }
  }
})
  • User IPs stay private: third parties see your server's IP
  • 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.

See First-Party Guide for details.

Partytown Support

Load scripts off the main thread using web workers.

export default defineNuxtConfig({
  modules: ['@nuxtjs/partytown', '@nuxt/scripts'],
  scripts: {
    partytown: ['plausible', 'fathom', 'umami'],
    registry: {
      plausible: { domain: 'example.com' }
    }
  }
})

Forward arrays are auto-configured for supported scripts.

GA4 has known issues with Partytown. GTM is not compatible. Consider Plausible, Fathom, or Umami instead.

SSR Social Embeds

Render X and Instagram embeds server-side without loading third-party JavaScript.

<ScriptXEmbed tweet-id="1754336034228171055">
  <template #default="{ userName, text, likesFormatted }">
    <!-- Full styling control via scoped slots -->
  </template>
</ScriptXEmbed>

<ScriptInstagramEmbed post-url="https://instagram.com/p/ABC123/">
  <template #default="{ html }">
    <div v-html="html" />
  </template>
</ScriptInstagramEmbed>
  • Zero third-party JavaScript
  • No cookies set by X/Instagram
  • User IPs not shared
  • All content served from your domain

Script Reload

Re-execute DOM-scanning scripts after SPA navigation:

const script = useScript('/third-party.js')
await script.reload()

SRI Integrity Hashes

export default defineNuxtConfig({
  scripts: {
    assets: {
      integrity: 'sha384' // or 'sha256', 'sha512'
    }
  }
})
export default defineNuxtConfig({
  scripts: {
    registry: {
      googleTagManager: {
        id: 'GTM-XXXX',
        defaultConsent: {
          ad_storage: 'denied',
          analytics_storage: 'denied'
        }
      }
    }
  }
})

New Registry Scripts

  • PostHog: Product analytics with feature flags
  • Google reCAPTCHA v3: Invisible bot protection
  • TikTok Pixel: Conversion tracking
  • Google Sign-In: One-tap authentication

Google Maps Color Mode

<ScriptGoogleMaps
  :map-ids="{ light: 'LIGHT_MAP_ID', dark: 'DARK_MAP_ID' }"
/>

Auto-switches with @nuxtjs/color-mode or manual color-mode prop.

Breaking Changes

YouTube Player

Aspect Ratio

Use ratio prop instead of deriving from width/height:

<ScriptYouTubePlayer
  video-id="..."
-  :width="1280"
-  :height="720"
+  ratio="16/9"
/>

Default is 16/9.

Placeholder Image

Default object-fit changed from contain to cover:

<ScriptYouTubePlayer video-id="..." placeholder-object-fit="contain" />

Multiple Players

Player instances are now properly isolated. Remove any workarounds for multiple players.

Google Tag Manager

onBeforeGtmStart Callback

Now fires for cached/pre-initialized scripts. Guard against multiple calls:

let initialized = false
useScriptGoogleTagManager({
  onBeforeGtmStart: (gtag) => {
    if (initialized)
      return
    initialized = true
    // your init code
  }
})

Type Augmentation

Templates reorganized. Run nuxi prepare after upgrading.