— EU AI Act, Article 50
Tells your visitors they are interacting with an AI system, and labels AI-generated content — in all 24 official EU languages, automatically. No dependencies, 7 kB, and nothing leaves the page.
01 Live demo
Change the language and watch every string follow. The label on generated content switches on hover.
Marked with data-ai-generated
plus data-ai-overlay.
This paragraph was drafted by a generative model, so it carries an inline label.
The floating notice at the bottom is the Article 50(1) disclosure. Replies you trigger are labelled automatically — the widget watches for new content, so streamed chat output is covered without extra code.
02 Install
recommended
Download disclose.min.js, drop it next to your other assets, point
the tag at it. One file, no dependencies, no network calls — there is nothing a CDN
adds. And your notice can never break because someone else’s domain lapsed.
convenient
Fine if you would rather not manage the file. Pin the version so an update can never change behaviour under you.
</body>Self-hosted:
<script src="/js/disclose.min.js"
data-mode="both" data-lang="auto" data-theme="auto"></script>
Or pinned from a CDN:
<script src="https://cdn.jsdelivr.net/npm/@kalbydot/kalby.disclose@1.0.0/dist/disclose.min.js"> </script>
That single line already gives you the chatbot notice. Everything below is optional.
One attribute. Add data-ai-overlay on images and video to place the
label on the media instead of after it.
<img src="hero.png" data-ai-generated> <p data-ai-generated>Drafted by our assistant.</p> <video src="clip.mp4" data-ai-generated="deepfake" data-ai-overlay></video>
Use ="deepfake" for artificially
generated or manipulated depictions of real people, places or events — it carries the
fuller Article 50(4) sentence.
By default the notice floats at the bottom of the page. To put it inside your chat panel instead, give it the container’s selector.
<script src="/js/disclose.min.js" data-chat-target="#support-chat"></script>
Open your site in a private window — a dismissal is remembered, so a normal window can hide the notice you are looking for.
You should see the notice within a second of load, and a label on everything you marked. In the browser console:
KalbyDisclose.getAuditLog() // timestamped record of what was shown KalbyDisclose.languages // the 24 codes it can render
No plugin needed. Install a footer-snippet plugin such as WPCode, then Code Snippets → Header & Footer and paste the script into the Footer box. Most themes and builders have their own custom-scripts field, which works just as well.
On a child theme, passing the site locale keeps the notice in your site’s language rather than the visitor’s:
add_action( 'wp_footer', function () { ?>
<script src="/js/disclose.min.js"
data-lang="<?php echo esc_attr( substr( get_locale(), 0, 2 ) ); ?>"></script>
<?php } );
To mark content in the block editor, select the block, open its options menu and choose Edit as HTML, then add the attribute to the tag. The block stays valid — Gutenberg does not flag it.
This whole route is tested end-to-end on WordPress 6.4 with a block theme (a child theme of Twenty Twenty-Three): the snippet above, the site locale flowing into the notice, and hand-marked blocks surviving the editor.
KalbyDisclose.resetDismissal() in the
console brings it back.
03 Options
| Attribute | Default | What it does |
|---|---|---|
data-mode | both | Chatbot notice, content labels, or both |
data-lang | auto | Reads <html lang>, then the browser |
data-theme | auto | Follows the visitor’s system preference |
data-position | bottom | Where the floating notice sits |
data-chat-target | — | Render inline inside your chat UI |
data-accent | #5b5bd6 | Match your brand colour |
data-learn-more-url | — | Adds a link to your AI policy |
data-remember | session | How long a dismissal sticks: session, persistent, always |
data-label-style | hover | hover, plain, or brand — see below |
04 The label
At rest the label reads the translated term with the sparkles the field has settled on — AI-generated, AI-gegenereerd, KI-generiert. Move a pointer over it and it crossfades to “AI sniffed” with Kalby’s dog. Try it on the labels in the demo above.
That order is deliberate. The chip is the legally operative label under Article 50(2) and 50(4), and “AI sniffed” is wordplay: on its own it does not tell a reader the content was produced by AI, and it says nothing at all to someone who does not read English. So the disclosing wording is what sits on the page, and the dog is a reward for looking closer — never a substitute.
Both faces share one grid cell, so the chip is as wide as the wider of the two and the text around it never reflows on hover.
:hover
— no timer, no auto-updating content, so none of the WCAG rules about moving content
apply. Touch devices, which have no hover, simply show the translated term. The
accessible name and the tooltip carry the full translated disclosure in every case.
Prefer it fixed? data-label-style="plain" drops the hover face,
brand gives you the dog alone.