Skip to main content

Next.js Scripts and embeds

Embeds

Pick a method

MethodUse it when
ConsentGateYou render the iframe in a React component and want a placeholder until the visitor allows its category.
The iframe blockerThe iframe comes from markup you do not render with a component, such as CMS or Markdown content.

Both keep the iframe's src out of the page until the category is allowed, so the embed's host receives no request before consent.

Gate an embed with ConsentGate

Wrap the iframe in ConsentGate in a Client Component:

components/video-embed.tsx
'use client';

import { ConsentGate } from 'c15t/next';

export const VideoEmbed = () => (
	<ConsentGate category="measurement">
		<iframe
			className="video-frame"
			sandbox="allow-scripts allow-same-origin allow-presentation"
			src="https://www.youtube-nocookie.com/embed/czTksCF6X8Y"
			title="YouTube video"
			allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
			allowFullScreen
		/>
	</ConsentGate>
);

Import VideoEmbed into any page or Server Component under the layout that mounts ConsentRoot; only this file needs 'use client'. The iframe stays out of the page until the visitor allows measurement, and a placeholder with a button that opens the preference dialog takes its place.

Pick the category that matches what the embed does. The example uses measurement for YouTube because its player measures views. A map or chat widget usually belongs under functionality or experience.

What the server HTML contains depends on how your layout passes consent state. ConsentGate covers the default, awaited and Pages Router layouts, the placeholder and its props.

Gate an iframe with the iframe blocker

ConsentRoot runs the iframe blocker in the browser by default. Give an iframe data-src instead of src, and a data-category:

Markup from your CMS
<iframe
  data-src="https://www.google.com/maps/embed?pb=YOUR_EMBED_ID"
  data-category="functionality"
  title="Store map"
></iframe>

The server HTML has no src, so nothing loads before hydration. After hydration, c15t sets src from data-src when the category is allowed and removes src when the category is withdrawn. It watches the page, so iframes added by client-side navigation are handled too. Add data-vendor with a vendor ID to also block the iframe while the visitor has turned that vendor off.

To turn the blocker off, pass options={{ iframeBlocker: false }} to ConsentRoot.

Verify the embeds

Open the production build in a private window with DevTools open, under a policy that asks for consent.

  1. View the page source. No iframe has a src pointing at youtube-nocookie.com or google.com/maps, and the Network panel shows no request to them.
  2. Allow the embed's category and save. The iframe loads.
  3. Withdraw the category and save. The page reloads without the embed.

The YouTube and Google Maps guides cover sizing and titles.