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
andads
- 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'],
},
],
},
})
Composable API
You can build your own UI using the built-in composable:
const {
preferences,
categoryMeta,
acceptAll,
denyAll,
acceptCategories,
resetPreferences,
hasUserMadeChoice,
isConsentExpired
} = useCookieConsent()
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)
})
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.