Why Vue.js Apps Need a Different Approach to Cookie Consent

Vue.js applications run almost entirely in the browser. Unlike server-rendered pages where each navigation triggers a fresh HTTP request, a Vue single-page application (SPA) loads once and then handles routing client-side. That architectural difference has real consequences for GDPR cookie consent.

Traditional cookie banners designed for multi-page sites often assume that scripts are loaded per page view. In a Vue SPA, third-party scripts like _ga from Google Analytics or _fbp from Meta Pixel may initialise once at app startup and persist across every subsequent route change. If those scripts fire before a visitor grants consent, the site is non-compliant under Article 5(3) of the ePrivacy Directive, regardless of whether a banner eventually appears.

The core requirement is straightforward: non-essential cookies must not be set until the user gives explicit, informed consent. Achieving that in a reactive JavaScript framework demands attention to script loading order, state management, and the distinction between server-side and client-side execution.

Cookie Categories in a Typical Vue Application

Before configuring consent, you need to know which cookies your Vue app actually sets. A cookie scanner can automate this, but understanding the common categories helps you plan your implementation.

CategoryExamplesConsent Required?Notes
Strictly necessaryPHPSESSID, csrf_token, session cookiesNoRequired for basic site function
Functionalpll_language, theme_preferenceYes (in the EU)Stores user preferences
Analytics_ga, _ga_*, _gidYesTracks page views and behaviour
Marketing_fbp, _gcl_au, li_fat_idYesUsed for ad targeting and retargeting

The distinction matters because your consent mechanism must block analytics and marketing cookies by default while allowing strictly necessary cookies to function immediately. Functional cookies occupy a grey area - under the GDPR, most Data Protection Authorities classify them as requiring consent unless they are genuinely essential to deliver the service the user explicitly requested.

Plain Vue 3: Adding a Cookie Banner via Script Tag

The simplest integration path for a Vue 3 application is adding a consent management script directly to your index.html file. This approach works because the script loads before Vue mounts, ensuring the banner appears and blocks non-essential cookies from the very first render.

Place the CMP script tag in the <head> section of your index.html, above any analytics or marketing scripts. The Vue.js installation guide in the Kukie.io Help Centre walks through the exact placement. The key principle is that your consent script must execute before any trackable script does.

This method avoids Vue's reactivity system entirely, which is an advantage. The banner operates independently of your Vue components, so it cannot be affected by component lifecycle issues or hydration mismatches.

Conditionally Loading Scripts After Consent

Once you have a consent banner in place, the next step is ensuring third-party scripts only load after the visitor accepts the relevant cookie category. There are two approaches in plain Vue.

The first is using type="text/plain" on script tags in your HTML. A compliant CMP will change these to type="text/javascript" only after consent is granted. The second is listening for a consent callback in your Vue app and dynamically injecting scripts via JavaScript when the appropriate category is accepted.

Both methods achieve the same outcome. The HTML attribute approach is simpler and keeps tracking scripts out of your Vue bundle. The callback approach gives you finer control and works well when you need to initialise analytics libraries that require JavaScript API calls rather than just a script tag.

Nuxt.js: Server-Side Rendering Adds Complexity

Nuxt introduces server-side rendering (SSR), which means your application runs on the server before the browser receives it. Cookies do not exist on the server. Any code that references document.cookie during SSR will throw an error, and even guarding with typeof window !== 'undefined' can produce hydration mismatches where the server-rendered HTML differs from the client-rendered result.

The safest pattern in Nuxt is to load your cookie consent script exclusively on the client side. In Nuxt 3, the useHead composable with tagPosition: 'head' combined with a client-only guard ensures the script only runs in the browser. Wrap consent-dependent logic in onMounted or use the <ClientOnly> component to prevent SSR conflicts.

For Nuxt-specific configuration details, the Nuxt.js cookie consent guide covers useHead, module integration, and head configuration in depth.

Nuxt Modules vs External CMP Script

The Nuxt ecosystem offers several cookie consent modules. These provide convenient composables and built-in UI components. The trade-off is that most are community-maintained and may lag behind regulatory changes. An external CMP script loaded via the <head> operates independently of the Nuxt version and receives updates from the CMP provider without requiring you to update a dependency.

If your site serves visitors across multiple jurisdictions, an external CMP also handles geo-detection and region-specific rules out of the box, something few Nuxt modules support natively.

SPA Route Changes and Consent Persistence

A frequently overlooked issue in Vue SPAs is what happens after consent is given. In a traditional multi-page site, the consent cookie is read on each new page load. In a Vue SPA, no new page load occurs when the user navigates between routes.

Your consent state must persist in a way that survives route changes but also respects the user's right to withdraw consent. Most CMPs store consent in a first-party cookie (commonly named something like cookie_consent_status or kukie_consent), which is read once at app initialisation. Vue's reactivity system can then hold the current consent state in a reactive ref or a Pinia store, allowing components to check whether analytics scripts should be active.

If a user withdraws consent mid-session, your app needs to respond immediately. That means removing or disabling scripts and clearing cookies that were set under the now-revoked category. The consent callback API pattern is useful here: listen for consent change events and react accordingly.

Google Consent Mode and Vue.js

Google Consent Mode v2 is a requirement for any Vue app using Google Analytics 4, Google Ads, or Google Tag Manager. It works by sending consent signals to Google's tags, allowing them to adjust their behaviour based on whether the user has granted or denied consent.

In a Vue application, you typically set default consent states (denied for analytics and advertising) before the Google tag loads, then update those states when the user interacts with the cookie banner. The implementation sits in your index.html before the gtag.js script, not inside Vue components. A properly configured CMP handles this automatically, sending consent('update', ...) calls when the user makes a choice.

If you use Google Tag Manager, the same principle applies: GTM must receive consent signals before firing any tags.

Common Mistakes in Vue Cookie Consent Implementations

Auditing Vue applications for cookie compliance reveals several recurring problems.

Loading analytics in main.js or App.vue onMounted. This fires the script as soon as the app mounts, before the user has any opportunity to interact with the banner. Analytics initialisation must be gated behind a consent check.

Using Vue plugins that set cookies on install. Some Vue analytics plugins call their initialisation function the moment you register them with app.use(). If you register such a plugin unconditionally, cookies are set before consent. Delay plugin registration until after consent is confirmed.

Ignoring the ePrivacy Directive in favour of GDPR alone. The GDPR defines how consent must be collected, but Article 5(3) of the ePrivacy Directive is the specific rule that requires prior consent for storing cookies. Both apply simultaneously.

Not testing with a cleared browser state. Developers often test with consent already granted from a previous session. Always test in a private browsing window to verify that no analytics cookies are set before consent.

Testing and Verifying Your Implementation

After adding cookie consent to your Vue app, verify it works correctly. Open Chrome DevTools, navigate to the Application tab, and clear all cookies and site data. Reload the page. Before interacting with the banner, check the Cookies panel. Only strictly necessary cookies should be present.

Accept all cookies via the banner, then check again. Analytics and marketing cookies should now appear. Withdraw consent (if your CMP supports preference changes), and confirm those cookies are removed. A thorough cookie banner testing checklist should cover each consent state and verify correct behaviour in private browsing mode.

Automated testing is also possible. Run a cookie audit against your deployed Vue application to catch any scripts that fire before consent. Kukie.io's scanner detects, categorises, and reports on every cookie your site sets, including those from third-party scripts embedded in your SPA.

Frequently Asked Questions

Does a Vue.js SPA need a cookie banner?

Yes. If your Vue app sets any non-essential cookies, such as analytics or marketing cookies, you need prior consent from visitors under the ePrivacy Directive and GDPR. The SPA architecture does not exempt you from these requirements.

Can I use a Vue component for cookie consent instead of a script tag?

You can, but a script tag in the HTML head is more reliable. It loads before Vue initialises, ensuring no tracking scripts fire prematurely. A Vue component only mounts after the app is ready, which may be too late if other scripts have already executed.

How do I block Google Analytics in Vue until consent is given?

Set Google Consent Mode defaults to denied before loading gtag.js. When the user grants consent, the CMP sends a consent update signal. This approach lets GA4 load with consent signals rather than requiring you to delay the entire script.

Is cookie consent different for Nuxt.js compared to plain Vue?

The legal requirements are identical. The technical implementation differs because Nuxt uses server-side rendering, where document.cookie is unavailable. You must ensure consent logic runs only on the client side to avoid SSR errors and hydration mismatches.

What happens if a user withdraws cookie consent in a Vue SPA?

Your app must immediately stop any tracking scripts and delete cookies that were set under the revoked category. Listen for consent change events from your CMP and react accordingly, either by removing scripts from the DOM or by calling their opt-out methods.

Do I need separate cookie consent for each Vue route?

No. Consent applies to the entire domain, not individual routes. Once a visitor grants or denies consent, that decision covers all pages within your SPA. The consent state is stored in a cookie that persists across route changes.

Take Control of Your Cookie Compliance

If you are not sure which cookies your Vue.js app sets, start with a free scan. Kukie.io detects, categorises, and helps you manage every cookie - so your visitors get a clear choice, and you stay on the right side of the law.

Start Free - Scan Your Website