Nuxt 3: Flexible Cookie Consent Module
criting

criting @criting

About: Full-stack web developer

Location:
Bulgaria
Joined:
Dec 19, 2020

Nuxt 3: Flexible Cookie Consent Module

Publish Date: Jun 19
0 0

A Simple, Flexible Cookie Consent Module for Nuxt 3 — Still in Development

Cookie banners have become a default requirement in modern websites — but most solutions I found for Nuxt were either too bloated, too opinionated, or overly complex just to get a consent banner working.

So I decided to build my own — headless, fully customizable, and Nuxt 3-native.

Introducing: nuxt-simple-cookie-consent

A lightweight module that gives you full control over cookie categories, script injection, consent logic, and expiration — while staying out of your way when it comes to styling and UI.


Why I Built This

Most cookie modules I tried:

  • Forced a UI I didn’t want
  • Didn’t let me control the UX
  • Were hard to integrate into my Nuxt/Vue composables
  • Didn’t handle script injection cleanly

I just wanted something simple: give me the logic, and let me build my own UI on top.


Features

Here’s what it currently supports out of the box:

  • Headless design – You build the banner, modals, toggles — I just give you the reactive state and logic
  • Categorized script control – Group scripts into analytics, ads, or anything you want
  • Support for multi-category scripts – e.g. a single script can belong to both analytics and ads
  • Required categories – Enforce required scripts that users can’t disable
  • Auto-injection and removal – Based on real-time preferences
  • Consent expiration – Re-prompt users after a configurable duration (e.g. 180 days)
  • Consent versioning – Force re-consent if your cookie policy changes
  • Event hooks – Listen to consent lifecycle events like:
    • onConsentAccepted
    • onConsentDenied
    • onCategoryAccepted(category)
    • onScriptsInjected(category)
    • onScriptsRemoved(category)
  • SSR-safe – All scripts only run on the client, avoiding hydration mismatch
  • Inline & pixel support – Use <script>, inline JS, custom HTML, <iframe>, etc.
  • Google Tag Manager Consent Mode support (gtag('consent', 'update', {...}))
  • Built-in dev helpers – resetPreferences(), isConsentExpired, debug-friendly structure

Example Nuxt Config

export default defineNuxtConfig({
  modules: ['nuxt-simple-cookie-consent'],
  cookieConsent: {
    cookieName: 'cookie_consent',
    expiresInDays: 180,
    consentVersion: '1.0.0',
    gtmConsentMapping: {
      analytics: 'analytics_storage',
      ads: 'ad_storage',
    },
    categories: {
      analytics: {
        label: 'Analytics',
        description: 'Used to improve performance.',
      },
      ads: {
        label: 'Ads',
        description: 'Helps personalize advertising.',
      },
    },
    scripts: [
      {
        id: 'gtag-main',
        src: 'https://www.googletagmanager.com/gtag/js?id=GA_ID',
        async: true,
        defer: true,
        categories: ['analytics'],
      },
      {
        id: 'gtag-inline',
        customContent: `
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', 'GA_ID');
        `,
        categories: ['analytics'],
      },
      {
        id: 'ads',
        src: 'https://ads.example.com/script.js',
        categories: ['ads'],
      },
      {
        id: 'fb-pixel',
        customHTML: `
          <iframe src="https://facebook.com/track.html" height="1" width="1" style="display:none"></iframe>
        `,
        categories: ['ads'],
      },
    ],
  },
})
Enter fullscreen mode Exit fullscreen mode

Composable API

You can build your own UI using the built-in composable:

const {
  preferences,
  categoryMeta,
  acceptAll,
  denyAll,
  acceptCategories,
  resetPreferences,
  hasUserMadeChoice,
  isConsentExpired
} = useCookieConsent()
Enter fullscreen mode Exit fullscreen mode

Hook into lifecycle events:

onConsentAccepted(() => {
  console.log('Consent accepted')
})

onConsentDenied(() => {
  console.log('Consent denied')
})

onCategoryAccepted(({ category }) => {
  console.log('Category accepted:', category)
})

onScriptsInjected(({ category }) => {
  console.log('Scripts injected for category:', category)
})

onScriptsRemoved(({ category }) => {
  console.log('Scripts removed for category:', category)
})
Enter fullscreen mode Exit fullscreen mode

Still Experimental

This module is actively being developed. While the core features work, it still needs more testing in various setups:

  • Do scripts load/unload correctly across multiple categories?
  • Is consent stored and respected properly?
  • How does it behave with third-party tag managers or inline scripts?

Contribute or Give Feedback

GitHub: https://github.com/criting/nuxt-simple-cookie-consent

  • Found a bug?
  • Have ideas for improvements?
  • Want to contribute?

Pull requests, discussions, and constructive critique are very welcome.

Comments 0 total

    Add comment