Add a cookie consent banner to Vue
The c15t Vue plugin puts the banner in your Vue 3 app as code. It holds tags until the visitor chooses and keeps Google Consent Mode v2 in sync.
Install c15t in a Vue 3 app
c15t is the open source consent library behind Inth Consent. It renders the banner from your own bundle and records each choice in your Inth project.
npm install c15t @c15t/integrationsAdd your Inth project URL to .env. Copy it from your Inth dashboard. Vite reads it at build time, so set it before you build.
.env
VITE_C15T_BACKEND_URL=https://your-project.inth.appAdd consentManifest() from c15t/vue/vite next to the Vue plugin. It gives the backend URL to the c15t plugin and writes no file into your project.
vite.config.ts
import vue from '@vitejs/plugin-vue';
import { consentManifest } from 'c15t/vue/vite';
import { defineConfig } from 'vite';
export default defineConfig({ plugins: [vue(), consentManifest()] });Code on this page comes from the c15t Vue quickstart, checked 28 October 2026.
For a Vue app that renders on the server, use the Nuxt cookie consent banner.
Install the Vue plugin
Install c15tVue from c15t/vue/vue-plugin in src/main.ts. It starts consent when the app mounts and loads the scripts that you give it.
src/main.ts
import { posthog } from '@c15t/integrations/posthog';
import { c15tVue, hosted } from 'c15t/vue/vue-plugin';
import { createApp } from 'vue';
import App from './App.vue';
createApp(App)
.use(c15tVue, {
mode: hosted(),
scripts: [
posthog({
id: 'phc_your_project_key',
initOptions: { cookieless_mode: 'never' },
loadMode: 'after-consent',
}),
],
})
.mount('#app');c15t/vue is the Nuxt module. Do not give it to app.use().
Mount the banner in App.vue
ConsentRoot renders the banner when the visitor’s policy asks for one. ConsentDialogLink opens the preferences again after the banner closes.
src/App.vue
<script setup lang="ts">
import { ConsentDialogLink, ConsentRoot } from 'c15t/vue/vue-plugin';
</script>
<template>
<ConsentRoot />
<main>
<h1>c15t with Vue</h1>
<p>PostHog loads after you allow measurement.</p>
</main>
<footer>
<ConsentDialogLink>Privacy settings</ConsentDialogLink>
</footer>
</template>Keep ConsentRoot in the root component, so it stays mounted. The components bring their own styles.
Hold scripts until consent
List each tag in the scripts option of c15tVue. With loadMode: 'after-consent', PostHog loads only after the visitor allows measurement.
Remove every other loader for PostHog, so it loads once and only through c15t. Vue scripts and embeds covers more vendors, iframes and the network blocker. The c15t integrations list the helper for each vendor.
Hold embeds until consent
Wrap third party iframes in ConsentGate. The iframe is not in the page until the visitor allows its category.
src/VideoEmbed.vue
<script setup lang="ts">
import { ConsentDialogLink, ConsentGate } from 'c15t/vue/vue-plugin';
</script>
<template>
<ConsentGate category="measurement">
<iframe
src="https://www.youtube-nocookie.com/embed/czTksCF6X8Y"
title="YouTube video"
loading="lazy"
allowfullscreen
/>
<template #placeholder>
<p>Allow measurement to load this YouTube video.</p>
<ConsentDialogLink>Choose video permissions</ConsentDialogLink>
</template>
</ConsentGate>
</template>Google Consent Mode v2 in Vue
The Google tag helper sends the Consent Mode v2 default before your config and an update after each choice. It ships in @c15t/integrations.
src/consent-scripts.ts
import { gtag } from '@c15t/integrations/google-tag';
export const scripts = [gtag({ id: 'G-XXXXXXXXXX', category: 'measurement' })];Add the helper to the scripts option of c15tVue in src/main.ts, next to PostHog.
Measurement maps to analytics_storage. Marketing maps to ad_storage, ad_user_data and ad_personalization.
By default the helper loads gtag.js before a choice. Google then gets a default that matches the current permissions. Set loadMode: 'after-consent' to send nothing to Google until the visitor accepts.
Show the right banner in each region
Your Inth project sets a policy for each region, such as opt in for the EU and UK or opt out for California. With hosted(), the browser asks your backend for the policy, and the backend reads the visitor’s location from that request. Regional policies need no extra code.
Test each region before launch. See how regional policies work.
When the banner appears
The browser asks your backend for the policy after the page loads, so the app works on any static host. The Vite plugin adds a small script to index.html that sends /init while your JavaScript downloads, so the banner can show sooner.
For a banner in the server HTML, use Nuxt. Measure your own pages before and after you add the banner.
Check that consent gates work
Build with vite build, run vite preview and open a private window with the Network tab open. Test under an opt in policy, such as the EU policy.
- Under an opt in policy, no PostHog request leaves the page before a choice.
- After Reject All and a reload, PostHog stays off.
- When you turn on measurement in Privacy settings, PostHog loads.
- When you turn measurement off, the page reloads without PostHog.
Choices post to your Inth project. Check that Inth has a record for each one. The c15t verify consent guide has the full release checklist.
Use Inth in production
c15t is open source. Point it at your Inth project, which hosts the backend and keeps the consent records. See Inth open source.
c15t also has a local mode with no backend. It keeps no consent records, so the docs advise against it in production.
Want to see what else your repo sends before consent? Run a free codebase scan.
Cookie consent banners for other frameworks
The same banner and the same Inth project work in other stacks. See the setup for Next.js, React, TanStack Start, Nuxt, Astro, Svelte, SvelteKit, HTML and JavaScript.
Questions about Vue consent
This setup is for a Vue 3 app built with Vite. Install the plugin from c15t/vue/vue-plugin.
For a Vue app that renders on the server, use the c15t Nuxt module. See the Nuxt cookie consent banner.
Add the c15t helper for the tag to the scripts option with loadMode: 'after-consent'. Then remove the tag’s own script.
Wrap the iframe in ConsentGate with the measurement category. The iframe is not in the page until the visitor allows it.
Use the c15t Google tag helper. It sends the default before your config and an update after each choice.
Yes. Set a policy for each region in your Inth project. c15t applies the policy that matches the visitor’s location. See regional policies.
c15t has a local mode with no backend, but it keeps no consent records. Use your Inth project in production.