Guides

First-Party Mode

The Problem

Every third-party script your site loads connects your users directly to external servers. Each request shares the user's IP address, and many scripts go further - the X Pixel accesses 9 browser fingerprinting APIs (including navigator.getBattery()), sets 5 tracking cookies (muc_ads, guest_id_marketing, guest_id_ads, personalization_id, guest_id), and phones home to 3 separate domains. Microsoft Clarity reads 10 fingerprinting APIs across 3 domains. Even Google Analytics at 154 KB sends data that can be correlated across sites.

Ad blockers rightfully block these requests, which breaks analytics for sites that depend on them.

How First-Party Mode Works

First-party mode puts you in control of your users' requests:

  1. Build time: Scripts are downloaded and served from your domain. Collection URLs are rewritten to local paths (e.g., google-analytics.com/g/collect/_scripts/p/ga/g/collect)
  2. Runtime: Nitro proxies requests back to the original endpoints, anonymizing user data before forwarding

Your users never connect directly to third-party servers. Third parties see your server's IP, not your users'. Requests are same-origin so no third-party cookies are set, and ad blockers don't interfere.

Usage

First-party mode is enabled by default. Add scripts to your registry:

nuxt.config.ts
export default defineNuxtConfig({
  scripts: {
    registry: {
      googleAnalytics: { id: 'G-XXXXXX' },
      metaPixel: { id: '123456' },
    }
  }
})

To disable globally:

nuxt.config.ts
export default defineNuxtConfig({
  scripts: {
    firstParty: false
  }
})

Or per script:

useScriptGoogleAnalytics({
  id: 'G-XXXXXX',
  scriptOptions: { firstParty: false }
})

Privacy Controls

Each script in the registry declares its own privacy defaults based on what data it needs. Privacy is controlled by six flags:

FlagWhat it does
ipAnonymizes IP addresses to subnet level in headers and payload params
userAgentNormalizes User-Agent to browser family + major version (e.g. Mozilla/5.0 (compatible; Chrome/131.0))
languageNormalizes Accept-Language to primary language tag
screenGeneralizes screen resolution, viewport, hardware concurrency, and device memory to common buckets
timezoneGeneralizes timezone offset and IANA timezone names
hardwareAnonymizes canvas/webgl/audio fingerprints, plugin/font lists, browser versions, and device info

Sensitive headers (cookie, authorization) are always stripped regardless of privacy settings.

Per-Script Defaults

Four privacy presets cover all scripts:

PresetFlagsScripts
Fullall flagsMeta Pixel, TikTok Pixel, X Pixel, Snapchat Pixel, Reddit Pixel
Heatmap-safeip, language, hardwareGoogle Analytics, Microsoft Clarity, Hotjar
IP onlyipIntercom, Crisp, Gravatar, Stripe, PayPal, YouTube, Vimeo, reCAPTCHA, Google Sign-In
None-GTM, PostHog, Plausible, Umami, Rybbit, Databuddy, Fathom, CF Web Analytics, Vercel, Segment, Carbon Ads, Lemon Squeezy, Matomo

Global Override

Override all per-script defaults at once:

nuxt.config.ts
export default defineNuxtConfig({
  scripts: {
    firstParty: {
      privacy: true, // Full anonymize for ALL scripts
    }
  }
})

Or selectively override specific flags:

nuxt.config.ts
export default defineNuxtConfig({
  scripts: {
    firstParty: {
      privacy: { ip: true }, // Anonymize IP for all scripts, rest uses per-script defaults
    }
  }
})

Supported Scripts

First-party mode supports all registry scripts:

Static Hosting

First-party mode requires a server runtime for the proxy endpoints. For static deployments (nuxt generate), scripts are still bundled with rewritten URLs but you'll need to configure platform rewrites manually.

The pattern is /_scripts/p/<alias>/:path*https://<original-domain>/:path*. Check Nuxt DevTools → Scripts or your Nitro server logs for the exact routes registered for your scripts.

Example for Vercel:

vercel.json
{
  "rewrites": [
    { "source": "/_scripts/p/ga/:path*", "destination": "https://www.google-analytics.com/:path*" },
    { "source": "/_scripts/p/gtm/:path*", "destination": "https://www.googletagmanager.com/:path*" },
    { "source": "/_scripts/p/meta/:path*", "destination": "https://connect.facebook.net/:path*" }
  ]
}

The same pattern applies to Netlify ([[redirects]] with :splat) and Cloudflare Pages (_redirects file). Only include rewrites for scripts you use.

First-party mode controls where requests go. Consent triggers control when scripts load. Use both:

<script setup>
const trigger = useScriptTriggerConsent()

useScriptGoogleAnalytics({
  id: 'G-XXXXXX',
  scriptOptions: { trigger }
})
</script>
First-party mode does not bypass GDPR consent requirements. You still need user consent before loading tracking scripts.

Troubleshooting

ProblemFix
Analytics not trackingCheck DevTools → Network for /_scripts/p/ requests. Check Nitro server logs for proxy errors
Stale scriptrm -rf .nuxt/cache/scripts and rebuild
Build download failsSet assets.fallbackOnSrcOnBundleFail: true to fall back to direct loading
DebuggingOpen Nuxt DevTools → Scripts to see proxy routes and first-party status