Volver al blog
Technical

Nuxt 3 Cookie Consent: The Complete Guide

Equipo de GetCookiesJanuary 4, 20258 min de lectura
NuxtVueImplementationTutorial

TLDR: Cookie consent in Nuxt 3 takes one config entry. Add to nuxt.config.ts, deploy, you're compliant. Full Google Consent Mode v2, no GTM needed.

Read full summary

Nuxt 3 makes configuration elegant. Cookie consent should match that elegance. One entry in nuxt.config.ts gives you GDPR compliance, Google Consent Mode v2, and script blocking. This guide covers the basics and advanced patterns.

Summary by Claude AI

Nuxt's Philosophy Applied to Compliance

Nuxt 3 is opinionated about simplicity. Configuration lives in one file. Composables replace boilerplate. Auto-imports save keystrokes.

Cookie consent should work the same way.

Most consent tools fight against this philosophy. They want you to install npm packages, create plugins, configure external dashboards, and debug why things don't work in SSR mode.

GetCookies follows the Nuxt way: add to config, deploy, done.

The 2-Minute Setup

// nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      script: [
        {
          src: 'https://getcookies.co/api/v1/widget/loader.js',
          'data-domain-id': 'YOUR_DOMAIN_ID',
          async: true
        }
      ]
    }
  }
})

Deploy. Refresh. You have a cookie banner.

You also have:

  • GDPR-compliant consent collection
  • Google Consent Mode v2 (all four signals)
  • Automatic script blocking until consent
  • Third-party pixel support (Meta, TikTok, Google)
  • Consent logging for audits

No npm install. No plugin file. No composable boilerplate.

Environment Configuration

Use runtime config for different environments:

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      getCookiesDomainId: process.env.GETCOOKIES_DOMAIN_ID || ''
    }
  },
  app: {
    head: {
      script: [
        {
          src: 'https://getcookies.co/api/v1/widget/loader.js',
          'data-domain-id': process.env.GETCOOKIES_DOMAIN_ID || '',
          async: true
        }
      ]
    }
  }
})
# .env
GETCOOKIES_DOMAIN_ID=dev-domain-id

# .env.production
GETCOOKIES_DOMAIN_ID=prod-domain-id

Create separate domains in GetCookies for localhost, staging, and production.

A Composable for Consent State

Want reactive consent state throughout your app? Create a composable:

// composables/useConsent.ts
export function useConsent() {
  const hasAnalytics = ref(false)
  const hasMarketing = ref(false)
  const hasPreferences = ref(false)

  const checkConsent = () => {
    if (typeof window !== 'undefined' && window.GetCookies) {
      hasAnalytics.value = window.GetCookies.hasConsent('analytics')
      hasMarketing.value = window.GetCookies.hasConsent('marketing')
      hasPreferences.value = window.GetCookies.hasConsent('preferences')
    }
  }

  const showPreferences = () => {
    window.GetCookies?.showPreferences()
  }

  const acceptAll = () => {
    window.GetCookies?.acceptAll()
  }

  const rejectAll = () => {
    window.GetCookies?.rejectAll()
  }

  onMounted(() => {
    checkConsent()
    window.addEventListener('getcookies:consent', checkConsent)
  })

  onUnmounted(() => {
    window.removeEventListener('getcookies:consent', checkConsent)
  })

  return {
    hasAnalytics: readonly(hasAnalytics),
    hasMarketing: readonly(hasMarketing),
    hasPreferences: readonly(hasPreferences),
    showPreferences,
    acceptAll,
    rejectAll
  }
}

Nuxt auto-imports composables from the composables folder. Use it anywhere:

<script setup>
const { hasAnalytics, hasMarketing, showPreferences } = useConsent()
</script>

<template>
  <div>
    <p v-if="hasAnalytics">Analytics: Enabled</p>
    <p v-if="hasMarketing">Marketing: Enabled</p>

    <button @click="showPreferences">
      Cookie Settings
    </button>
  </div>
</template>

Conditional Script Loading

Method 1: useHead

Load scripts reactively based on consent:

<script setup>
const { hasAnalytics } = useConsent()

useHead(() => ({
  script: hasAnalytics.value ? [
    {
      src: 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXX',
      async: true
    }
  ] : []
}))
</script>

Method 2: Data Attributes

Let GetCookies manage script activation:

// nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      script: [
        {
          src: 'https://getcookies.co/api/v1/widget/loader.js',
          'data-domain-id': 'YOUR_DOMAIN_ID',
          async: true
        },
        {
          src: 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXX',
          type: 'text/plain',
          'data-cookieconsent': 'analytics'
        }
      ]
    }
  }
})

The type: 'text/plain' prevents execution. GetCookies activates it after consent.

SSR: No Special Handling

GetCookies runs client-side. For SSR-safe components:

<script setup>
const hasConsent = ref(false)

onMounted(() => {
  hasConsent.value = window.GetCookies?.hasConsent('analytics') ?? false
})
</script>

<template>
  <ClientOnly>
    <PersonalizedContent v-if="hasConsent" />
    <template #fallback>
      <GenericContent />
    </template>
  </ClientOnly>
</template>

<ClientOnly> prevents hydration mismatches. The fallback shows during SSR.

TypeScript Support

Add type definitions:

// types/getcookies.d.ts
declare global {
  interface Window {
    GetCookies?: {
      hasConsent: (category: 'analytics' | 'marketing' | 'preferences') => boolean
      showPreferences: () => void
      acceptAll: () => void
      rejectAll: () => void
    }
  }
}

export {}

Reference in tsconfig:

{
  "compilerOptions": {
    "types": ["./types/getcookies"]
  }
}

Common Patterns

Footer Cookie Link

<!-- components/Footer.vue -->
<script setup>
const { showPreferences } = useConsent()
</script>

<template>
  <footer class="py-8 border-t">
    <button
      @click="showPreferences"
      class="text-sm text-gray-500 hover:underline"
    >
      Cookie Settings
    </button>
  </footer>
</template>

Consent-Gated Analytics

<!-- components/Analytics.vue -->
<script setup>
const { hasAnalytics } = useConsent()

watch(hasAnalytics, (enabled) => {
  if (enabled) {
    useHead({
      script: [{
        innerHTML: `
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', 'G-XXXXXXXX');
        `
      }]
    })
  }
}, { immediate: true })
</script>

<template>
  <!-- No visible output -->
</template>

Optional: Creating a Module

For multi-project reuse, create a local Nuxt module:

// modules/getcookies.ts
import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
  meta: {
    name: 'getcookies',
    configKey: 'getCookies'
  },
  defaults: {
    domainId: ''
  },
  setup(options, nuxt) {
    if (!options.domainId) {
      console.warn('[GetCookies] No domain ID provided')
      return
    }

    nuxt.options.app.head.script = nuxt.options.app.head.script || []
    nuxt.options.app.head.script.push({
      src: 'https://getcookies.co/api/v1/widget/loader.js',
      'data-domain-id': options.domainId,
      async: true
    })
  }
})

Use it:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['./modules/getcookies'],
  getCookies: {
    domainId: 'YOUR_DOMAIN_ID'
  }
})

Deployment

Vercel

vercel --prod

Netlify

# netlify.toml
[build]
  command = "npm run build"
  publish = ".output/public"

Cloudflare Pages

// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'cloudflare-pages'
  }
})

Troubleshooting

Hydration mismatch warnings? Wrap consent-dependent content in <ClientOnly>.

Script not loading?

  1. Check domain ID is correct
  2. Verify domain is added in GetCookies dashboard
  3. Check Network tab for script loading

Consent not updating? Ensure event listeners are in onMounted:

onMounted(() => {
  window.addEventListener('getcookies:consent', handler)
})

Performance Impact

Metric Impact
Bundle size +~1.6 KB loader (gzipped); banner ~20 KB, loaded async
LCP No impact
FID No impact
CLS No impact

Your Lighthouse scores stay green.

What You Don't Have to Do

  • Install an npm package
  • Create a plugin file
  • Configure GTM triggers
  • Read Consent Mode documentation
  • Debug SSR timing issues
  • Wonder if consent actually works

One config entry. Full compliance. The Nuxt way.


Ready to add cookie consent to your Nuxt app?

Get your domain ID in 60 seconds

G

Equipo de GetCookies

Escrito y mantenido por el equipo de GetCookies en Getia AS, en Oslo (Noruega). Este artículo es información general sobre el consentimiento de cookies, no asesoramiento jurídico.

Escanea tu propio sitio gratis

El plan gratuito muestra el banner en un sitio con tres escaneos de cookies al mes. Sin tarjeta, sin llamadas comerciales.