GatedFrame for Next.js
Show a third-party iframe only after the visitor consents, with a placeholder until then.
What it does
Renders a placeholder instead of the iframe until its category is granted. The placeholder says which cookies are needed and has a button that opens the preferences dialog. Once the visitor agrees, the iframe appears in its place, without a reload.
Use it for embeds that set cookies: YouTube, Vimeo, Google Maps, Spotify, social posts, Calendly. For iframes in HTML you do not render yourself, such as CMS or Markdown content, use Block embeds.
Add it
"use client";
import { GatedFrame } from "@cookieyes/nextjs";
export function VideoEmbed() {
return (
<GatedFrame
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
category="functional"
width={560}
height={315}
title="Product tour"
/>
);
}Video and map embeds are usually functional; social and ad embeds are usually advertisement. The category must exist in your categories list.
Props
| Name | Type | Default | Description |
|---|---|---|---|
srcrequired | string | None | The iframe URL, used once If omitted: Required. Omitting it is a compile-time type error: there is no default. |
categoryrequired | ConsentCategory | None | The consent category that gates rendering the real iframe. If omitted: Required. Omitting it is a compile-time type error: there is no default. |
placeholderoptional | ReactNode | None | Custom content shown instead of the iframe until consent for If omitted: Shows our own default placeholder (translatable via the |
...restoptional | Omit<IframeHTMLAttributes<HTMLIFrameElement>, "src" | "category" | "placeholder"> | None | Every other standard If omitted: No extra iframe attributes are applied beyond |
Every other <iframe> attribute (width, height, title, allow, ...) is passed to the iframe once it appears.
Change the placeholder
Pass your own element as placeholder:
"use client";
import { GatedFrame, useConsentActions } from "@cookieyes/nextjs";
function VideoPlaceholder() {
const { showPreferences } = useConsentActions();
return (
<div className="video-placeholder">
<p>This video is hosted by YouTube and needs functional cookies.</p>
<button type="button" onClick={showPreferences}>
Cookie settings
</button>
</div>
);
}
export function VideoEmbed() {
return (
<GatedFrame
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
category="functional"
width={560}
height={315}
title="Product tour"
placeholder={<VideoPlaceholder />}
/>
);
}To only change the default text, set gatedFrame.placeholder and gatedFrame.action in i18n; see Translations. To style the default placeholder, target .cy-frame-placeholder in your CSS.
Good to know
Give the placeholder the same size as the iframe, or the page jumps when it swaps. Once the iframe has appeared, withdrawing consent does not remove it in the current page; it is blocked again on the next page load.
Common mistakes
The embed never appears, even after accepting.
The category is not in your categories list, or the visitor granted a different one. A development build names an unknown category in the console.
The placeholder flashes on every load, even after consent. Expected: consent is only known in the browser, so the placeholder renders first. Give it the iframe's size so nothing moves.
Next steps
- GatedScript: the same idea for scripts
- Block embeds: iframes in HTML you do not render yourself
- Translations: the placeholder text in every language