---
title: ConsentGate
description: Render an iframe or widget in Nuxt only while its consent category
  is allowed, with the globally registered ConsentGate and a placeholder slot.
group: frameworks
lastModified: "2026-10-10T16:01:45+01:00"
---
## Wrap an embed in `ConsentGate`

The Nuxt module registers `ConsentGate` globally. Put the embed in the
default slot and a placeholder in the `placeholder` slot:

```vue title="app/components/VideoEmbed.vue"
<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>
```

The iframe is absent from the page until the visitor allows measurement. The
placeholder uses `ConsentDialogLink` so the visitor can open preferences
from it.

## What ConsentGate renders

`ConsentGate` renders its default slot while the visitor's effective
permission for `category` is granted, and its `placeholder` slot otherwise.
It adds no wrapper element. While permission is denied, the default slot
does not exist in the DOM, so an iframe or widget inside it sends no
requests. When the visitor withdraws permission, Vue removes the slot
content.

Permission is the same value `useConsent()` returns for the category. It can
be granted under an opt-out policy before the visitor has recorded a choice,
and a privacy signal such as Global Privacy Control can deny a category the
visitor granted.

Without a `placeholder` slot, the gate renders the same placeholder as the
React and Svelte gates. It shows the `consentGate.title` text with the
category name, and a button labelled with `consentGate.actionButton` that
opens the preference dialog. Under a strict policy that leaves the category
out, no choice can allow the content, so the placeholder shows
`consentGate.policyBlocked` and no button. The text is in the visitor's
language once init has delivered copy, and in English until then. The
placeholder is a card styled by your theme tokens and the
`--consent-gate-placeholder-*` variables. A `placeholder` slot replaces it
entirely.

To restyle the built-in placeholder instead, set its parts under
`components['consent-gate']` in the options. `root` is the card, and
`title` and `button` are its text and button. Use Vue attribute names such as `class` and `style`. The
`consentGate`, `consentGateTitle` and `consentGateButton` theme slots reach
the same parts. The placeholder carries
`data-testid="consent-gate-placeholder"`, its title
`data-testid="consent-gate-title"` and its button
`data-testid="consent-gate-button"`.

`ConsentGate` also adds its `category` to the categories the preference
dialog lists, so the button opens a dialog where the visitor can allow it.

## During server rendering

When the server resolves the policy, in the default `manifest()` mode or `hosted()`, the server
reads the visitor's consent cookie and evaluates the category before it renders. A
visitor who allowed the category gets the iframe in the first HTML, and a
visitor who has not gets the placeholder. On prerendered and cached routes,
and with `ssr: false`, every visitor gets the placeholder first, and the
iframe replaces it once the browser resolves the policy.

## Props and slots

|Name|Kind|Type|Behavior|
|--|--|--|--|
|`category`|Prop, required|`'necessary' \|'functionality' \|'measurement' \|'experience' \|'marketing'`|The category whose permission gates the default slot.|
|`default`|Slot||The gated content, such as an iframe.|
|`placeholder`|Slot||Shown while the category is denied.|

## Accessibility

Give the iframe a descriptive `title`. Keep a way to reach the content
without the embed, such as a link or a transcript, for visitors who decline
the category. A policy can fix a category as denied, so opening preferences
does not guarantee the visitor can allow it.

## Verify

View the page source in a private window. It holds the placeholder and no
`youtube-nocookie.com` iframe. Allow the category in preferences and save:
the iframe appears and its requests start. Reload and view the source again:
the iframe is now in the server HTML. Withdraw the category and save, and the
page reloads without the iframe.

## Next steps

* [Embeds](/docs/frameworks/nuxt/embeds) compares `ConsentGate` with the
  iframe blocker.
* [YouTube](/docs/integrations/youtube) and
  [Google Maps](/docs/integrations/google-maps) show complete embeds.
