Consentl with Nuxt

Add the Consentl loader to Nuxt 3 and 4 with app.head and tagPriority 0, so it renders before every other script.

Loader first in <head>
Yes

The loader must be the first script in <head> and synchronous. Nuxt's head manager (Unhead) sorts <head> tags by weight; lower weights render first:

Tag Weight
charset −20
viewport −15
title 10
async script 30
sync script 50
stylesheet 60
Nuxt module entry 80

tagPriority: 0 places the loader before every other script. "critical" (weight 42) would still come after async scripts.

nuxt.config.ts

export default defineNuxtConfig({
  app: {
    head: {
      script: [
        {
          src: `https://api.consentl.com/v1/loader.js?k=${process.env.NUXT_PUBLIC_CONSENTL_SITE_KEY}&l=en`,
          tagPosition: "head",
          tagPriority: 0,
        },
      ],
    },
  },
});

Language per request (@nuxtjs/i18n)

Use the same options in app.vue:

const { locale } = useI18n();
useHead({
  script: [{ src: computed(() => `https://api.consentl.com/v1/loader.js?k=${key}&l=${locale.value}`), tagPosition: "head", tagPriority: 0 }],
});

Changing the language on the client does not reload the banner; the new language applies on the next full page load.

Other tags (app.head or useHead)

Give every tag that must wait for consent type: "text/plain" and its Consentl category. Nuxt writes it as it is, the browser does not download it, and Consentl runs it once after consent:

script: [
  { src: loader, tagPosition: "head", tagPriority: 0 }, // the Consentl loader, as above
  { src: "https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX", type: "text/plain", "data-consentl": "analytics" },
  {
    innerHTML: "window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag('js',new Date());gtag('config','G-XXXXXXX');",
    type: "text/plain",
    "data-consentl": "analytics",
  },
],

A plain { src, async: true } tag is held on the Business plan too, and runs only once even though Nuxt adds a second copy of it while the page starts, but the browser downloads it before consent. In our test (Nuxt 4.6, a Google tag): plain async tag, one request before consent and one run after it; type: "text/plain", no request before consent and one run after it.

Check that it works

View the page source: the loader is the first <script> in <head>. Then follow the checks in Any website. Client-side navigation needs nothing extra, and Nuxt's page data (__NUXT_DATA__, window.__NUXT__) is never held back. Tested with Nuxt 4.6.

Consent Mode needs the Pro plan or higher, automatic blocking of known trackers the Business plan. Tags written in the page HTML (for example through app.head) are requested before consent unless you mark them as shown in Other tags (see also Any website).

Limitations

  • Do not add the loader a second time from a component or plugin: it must load once per document.
  • If you send a Content Security Policy, allow https://api.consentl.com (see Any website).

Stuck? Write to [email protected] — we answer in English on business days.