Why it matters
An editor pastes a YouTube URL. WordPress turns it into an iframe. From then on, every visitor’s browser contacts Google before anyone has been offered a choice.
Measured on a plain request, with no playback and no scripts run:
6
cookies set by www.youtube.com/embed/… — four of them identifiers that live about six months.
0
cookies from www.youtube-nocookie.com — where this plugin loads YouTube from after the click.
| Request | Cookies set |
|---|---|
www.youtube.com/embed/… | 6 — four of them ~six-month identifiers |
www.youtube-nocookie.com/embed/… | 0 |
| A WordPress-to-WordPress oEmbed preview | 1, lifetime one year |
The usual answer is a cookie banner. That is the expensive one: a platform to run, a record to keep, a prompt on every visit, and slower pages. The Zwei-Klick-Lösung removes the obligation instead of managing it — if nothing third-party loads until the visitor asks, there is nothing to announce at page load. The consent is the click.
How it works
You keep writing posts as before. Paste a URL, WordPress makes the embed, and editors still see the normal embed in the block editor.
Visitors see a placeholder instead — rendered on the server, so it is there before any JavaScript runs: the provider’s name, one sentence on what loading means, a real Load button, and a plain link to the content.
On the click, that one embed loads — from the privacy-preserving address where the provider has one. Nothing else loads with it, and nothing loads for embeds the visitor did not ask for.
See it working
This is not a screenshot. The plugin is running on this page, and below is a real YouTube embed it has gated: nothing was requested from YouTube to show it to you. Press the button, and only then does the video load — from youtube-nocookie.com.
The showcase page runs every provider on one page. Open developer tools, watch the Network tab, and reload: every request goes to this site. Press one button and only that provider appears.
What you get
- Works on activation No configuration, no account, no external service — activate it, and every third-party embed on the site is gated.
- Server-rendered placeholders Replaces third-party iframes, embed SDK scripts and legacy
<embed>/<object>markup on the server — so it still works with JavaScript off, and the fallback link always goes somewhere real. - Gates by host, not by allowlist Thirty-six providers are recognised by name — every embed type WordPress core knows about — and anything else third-party is gated anyway. The failure mode is a less specific label, never an ungated tracker.
- Survives minified HTML Attribute quotes stripped, newlines inside tags — the single most common reason competing implementations pass review and then silently fail in production. Lazy-loaded markup (
data-src) and content delivered over AJAX and the REST API — “load more”, infinite scroll — are gated too. - Privacy-preserving endpoints Where a provider offers one, the embed loads from it after the click:
youtube-nocookie.com, Vimeo withdnt=1. - Rebuilt from an attribute safelist
sandboxis preserved exactly,autoplaynever survives, inline styles and event handlers are never copied. - Accessible by design A named group, a real button, visible focus, sufficient contrast, and focus kept after loading — zero axe-core violations in CI.
- Feeds and resource hints, too Strips
preconnectanddns-prefetchhints pointing at gated providers, and removes embeds from feeds and excerpts rather than showing a placeholder nobody can press. - Poster images, from your library An optional poster image per embed — never fetched from the provider — and an optional link to the provider’s own privacy policy in each panel.
- Restyle it without CSS Colours (including a separate dark-mode set, and any of your theme’s own palette colours by name), corners, borders, shadow, spacing, button size and shape, and where the panel sits over a poster — all with a live preview and an automatic contrast check. Four one-click starting points if you would rather not fiddle.
- Add a provider without code Name any embed host on the Providers tab and it gets the same notice, button text, icon and privacy-policy controls as a built-in. Unknown hosts are gated either way — this just gives yours a name.
- Optional consent memory A withdrawal block or
[calucon_embed_gate_withdraw]shortcode to put on your privacy page, and an optional bridge to your existing consent platform. Both off by default; both fail closed. - Never phones home No telemetry, no CDN assets, no outbound request from your server or your visitors’ browsers, on any path, for any reason.
Languages
EnglishDeutschDeutsch (Sie)Deutsch (Österreich)Deutsch (Schweiz)Deutsch (Schweiz, Du)
Set the site language and the plugin follows — the placeholder your visitors see, all five settings tabs and the editor controls. The texts you type yourself are registered for WPML and Polylang, and further languages are welcome on translate.wordpress.org.
A look at the settings


Works with what you already run
Caching and optimisation plugins. Gating happens on the server, so the page a cache stores is the gated one:
W3 Total CacheWP Super CacheLiteSpeed CacheAutoptimizeWP Fastest CacheSiteGround OptimizerWP Rocket
Consent platforms, through the optional bridge. It only reads the platform’s answer; with any other platform, or no answer, gating stands:
WP Consent APIComplianzCookiebotCookieYesBorlabs Cookie 3Real Cookie Banner
Page builders. Elementor’s HTML and video widgets are gated out of the box; for a builder that renders outside the content filters, whole-page gating reads the finished page instead.
Multilingual sites:
WPMLPolylangTranslatePressWeglot
Every month these claims are re-tested on a real WordPress against the current versions of the plugins that are free to install; the ones that are not — WP Rocket, Borlabs Cookie, WPML, Weglot, Cookiebot’s banner — are tested against simulations of their documented behaviour.
Install
- From your dashboard: Plugins → Add New, search for “Calucon Third-Party Embed Gate”, Install, Activate.
- From the directory: wordpress.org/plugins/calucon-third-party-embed-gate.
- From source: the latest GitHub release, then Plugins → Add New → Upload Plugin.
It was called Consent Gate until August 2026. The name changed during WordPress.org review, to make clear that it gates third-party embeds rather than being a consent management platform, and in 0.9.0 the internal identifiers were renamed to match — filters, the [calucon_embed_gate_withdraw] shortcode, the withdrawal block, the wp calucon-embed-gate CLI namespace and the theme template directory. That was done deliberately before the directory listing went live, while no installed site existed to break; there are no legacy aliases. The .cg-embed classes, --cg-* custom properties and data-cg-* attributes are unchanged, so custom CSS still applies.
Activation is the whole setup — everything on the settings screen is optional.
Requires WordPress 5.9 or newer and PHP 7.4 or newer. No build step, no runtime dependencies.
Making it yours
- Settings screen (Providers / Detection / Appearance / Consent memory / Status & tools): per-provider toggles, custom button and note text, own-host and never-gate lists, appearance presets and colour pickers with a live readability check — no CSS needed.
- CSS custom properties on
.cg-embed(--cg-bg,--cg-fg,--cg-accent) for restyling without specificity wars. - Theme template override: copy
templates/placeholder.phpinto{your-theme}/calucon-embed-gate/. - Filters for everything that matters — adding a provider is a ten-line filter in
functions.php. - WP-CLI:
wp calucon-embed-gate scananswers “is every embed on this site gated?” and speaks JSON, so it can run in CI.
API reference — every filter and action with its signature, firing point, return contract and a runnable example, plus the settings schema, the WP-CLI commands, the placeholder markup contract and the front-end JavaScript surface.
Customizing guide — the same ground in prose: what a customization must not break, and why.
Questions people actually ask
Does this make my site GDPR compliant?
No plugin can claim that, and this one does not. Calucon Third-Party Embed Gate is a technical measure: it prevents the requests, and the storage they trigger, until the visitor asks. Whether your site’s overall processing is lawful depends on things a plugin cannot know. Your privacy policy still has to name the providers you embed from.
So I do not need a cookie banner?
Not for the embeds. If nothing third-party loads at page load, there is nothing to announce at page load. If the rest of your site sets cookies that need consent — analytics, ads, a marketing pixel — that is a separate question this plugin does not answer.
I already run Complianz / Cookiebot / Borlabs. Do they fight?
No. By default Calucon Third-Party Embed Gate ignores the banner and keeps gating, and nothing double-blocks — the placeholder contains no iframe or script for a banner’s blocker to catch. If you would rather have one decision instead of two, turn on the consent platform bridge and a consent given in your platform loads the embeds automatically.
Does loading="lazy" count as consent?
No. Lazy loading defers the request to scroll time; it is still made without consent. Lazy iframes are gated like any other.
I use a caching or minification plugin. Does that break it?
Not the gating. That happens on the server, so the page a cache stores is the gated one, and minified HTML is expected rather than a problem. Loading the plugin’s own script deferred, combined into a bundle or injected after the page has finished all work too.
One setting is worth knowing about: delay JavaScript until interaction. It holds every script back until the visitor first interacts, and that interaction is spent switching the scripts on — so the first click on a Load button does nothing and the visitor has to click again. Nothing third-party is contacted by the extra click, but the placeholder feels broken. Since 1.0.0, Status & tools names the three files to paste into your optimisation plugin’s exclusion list, and where that plugin keeps it.
Assets on a CDN hostname count as your own. Most CDN plugins filter the WordPress functions that say where your files live, and everything from that host is then yours. A CDN that rewrites the finished page instead is invisible to that, so since 1.0.0 scripts and stylesheets on a /wp-content/ or /wp-includes/ path are left alone whatever host serves them — never iframes, and never images.
An embed from my page builder is not gated
Elementor’s HTML and video widgets are gated out of the box — the video widget builds its player from JSON, with no iframe to find, and 1.0.0 gates it anyway. Other builders render outside WordPress’s content filters: turn on “Gate the whole page output” under Detection and the plugin reads the finished page instead. That is off by default because whole-page buffering can conflict with other buffering plugins.
What it is not
Calucon Third-Party Embed Gate is not a consent management platform. It does not produce consent records for accountability purposes, it does not scan your site for trackers, and it makes no legal claims about it. If you need a documented Art. 7(1) consent record, you need a CMP — and Calucon Third-Party Embed Gate will sit alongside it happily.
Support and security
- Bugs and feature requests: GitHub issues.
- Security: report privately through GitHub’s private vulnerability reporting, not a public issue. Any way to make a page contact a third party before the click counts as a vulnerability.
- Support the work: Ko-fi. Entirely optional — the plugin is GPL and has no paid tier.
Calucon Third-Party Embed Gate is built and maintained by Calucon. It grew out of gating the embeds on this very site, which is why the numbers on this page are measurements rather than estimates.
