Configuration

Categories, cookies, colors, links, and the intelligent banner.

Configuration

All options live under the cookieConsent key in nuxt.config.ts.

Options

OptionTypeDefaultDescription
localestring'en'Initial UI locale. Changeable at runtime via $consent.setLocale().
fallbackLocalestring'en'Locale used when a key is missing in the active locale.
colorsPartial<ColorOptions>shadcn-like defaultsCSS color values used by the built-in components.
darkColorsPartial<ColorOptions> | falseshadcn-like dark defaultsUsed instead of colors under a .dark ancestor — the class Nuxt's color mode (and Nuxt UI) puts on <html>. false keeps colors in dark mode.
textsRecord<string, any>EN/DE/ES/FR built-insTranslations, deep-merged over the defaults.
linkMapRecord<string, string>{ privacy, imprint }Maps {placeholder} link tokens used in texts to routes.
categoriesRecord<string, CategoryOptions>{ necessary: { readonly: true } }The cookie and tracking categories your site uses.
cookieNamestring'cookie_consent'Name of the cookie that stores the decision. Renaming it makes every visitor decide once more.

CategoryOptions

interface CategoryOptions {
  readonly?: boolean        // user cannot toggle (e.g. necessary)
  kind?: 'cookie' | 'tracking'  // default 'cookie' — see below
  description?: LocalizedString // shown in the modal (falls back to the i18n key)
  requiresBanner?: boolean  // category-level; overrides the per-cookie heuristic
  defaultEnabled?: boolean  // state before the visitor chooses — see below
  cookies?: CookieDefinition[]
}

interface CookieDefinition {
  id: string                // cookie name, e.g. '_ga'
  descriptionKey: string    // i18n key for the description
  provider: LocalizedString // e.g. 'Google LLC'
  duration: LocalizedString // e.g. '2 years', or { en: '2 years', de: '2 Jahre' }
  requiresBanner?: boolean  // defaults to true
}

// one string for every locale, or one per locale — see Internationalization
type LocalizedString = string | Record<string, string>

The intelligent banner (requiresBanner)

The module shows the initial consent banner only if necessary:

  • A non-essential cookie that requires a banner (analytics, marketing): omit requiresBanner or set it to true.
  • A non-essential cookie that should not trigger a banner (e.g. a theme preference set on-demand): set requiresBanner: false, and manage it with useConsentCookie so it's only written after consent.

If all non-essential cookies set requiresBanner: false, no banner appears on first visit — only the floating settings button. See Preferences without a banner for the theme and language pattern: the modal asks when the visitor first uses the feature, and nothing is stored before.

Cookies vs cookieless tracking (kind)

  • kind: 'cookie' (default) — backed by real device storage. The modal renders the provider/duration table from cookies[]; the per-cookie requiresBanner decides the banner.
  • kind: 'tracking' — something that is not a cookie, e.g. cookieless analytics (Umami, Plausible) or session replays. No cookies[]; the modal renders a labelled toggle with the category description. A tracking category shows the banner only when its category-level requiresBanner is true.

categories: {
  analytics: {
    kind: 'tracking',
    requiresBanner: false,     // opt-out: no banner, a toggle in the FAB / settings
    description: 'Cookieless usage analytics — no cookie, no device storage.',
  },
}

Default state (defaultEnabled)

What a visitor has before making a choice:

CategoryStarts
necessaryalways on
kind: 'tracking' without a banneron — that is what an opt-out means: it runs until the visitor switches it off
everything else (cookie categories, banner-gated tracking)off until consent

defaultEnabled overrides this per category. Use defaultEnabled: false for an opt-in without a banner — e.g. session replays or heatmaps, which capture on-screen content and need an explicit yes, but shouldn't force a banner on every visitor:

categories: {
  replays: {
    kind: 'tracking',
    requiresBanner: false,
    defaultEnabled: false,     // off until switched on from the FAB / settings
    description: 'Records clicks and scrolling to improve the pages. Off unless you switch it on.',
  },
}

Gate the matching script on the state: useNuxtApp().$consent.state.value.replays === true.

Full example

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@websideproject/nuxt-cookie-consent'],

  cookieConsent: {
    locale: 'en',
    fallbackLocale: 'en',

    linkMap: {
      privacy: '/privacy-policy',
      imprint: '/imprint',
    },

    categories: {
      necessary: { readonly: true },
      preferences: {
        cookies: [
          {
            id: 'theme_preference',
            descriptionKey: 'cookies.preferences.theme.description',
            provider: 'Our Website',
            duration: '1 year',
            requiresBanner: false,
          },
        ],
      },
      analytics: {
        cookies: [
          {
            id: '_ga',
            descriptionKey: 'cookies.analytics.ga.description',
            provider: 'Google LLC',
            duration: '2 years',
          },
        ],
      },
    },

    texts: {
      en: {
        cookies: {
          preferences: {
            theme: { description: 'Saves your selected theme (dark/light).' },
          },
          analytics: {
            ga: { description: 'Used by Google Analytics to distinguish users.' },
          },
        },
      },
    },
  },
})

See Internationalization for the full text structure, and Usage for wiring it all together.

Need a Landing Page?

Modern landing pages with optional modules (blog, docs, forms, i18n). Let's discuss your project.

Build Your MVP

Full-stack SaaS development. Expert in database design, multi-tenancy, and scalable architecture.

Deployment Help

Dockerize your backend, set up CI/CD pipelines, deploy to Cloudflare or Hetzner. Early-stage setup.

Suggest a SaaS Tool

Missing a calculator or tool? Suggest what you'd like to see on our site.