Klaro
Klaro — open source, service-first, and writable from your own UI.
npm i @libconsent/klaroimport { ConsentProvider } from "@libconsent/core";
import { klaro } from "@libconsent/klaro";
<ConsentProvider adapter={klaro({ config: klaroConfig })}>
{children}
</ConsentProvider>;Klaro is open source and self-hostable, and it is
service-first: its config lists each service and the purposes that service
serves. That maps onto libconsent exactly — and because Klaro accepts consent
back, it is one of the platforms where the shadcn banner and
useConsentForm() can replace its UI entirely.
Options
| Option | Default | |
|---|---|---|
config | window.klaroConfig | Klaro's own config. Set here, it lands on window.klaroConfig before the script boots. |
src | kiprotect CDN | Where to load Klaro from. |
manual | false | The script is already on the page. |
purposes | keyword matching | Map Klaro purposes onto libconsent categories. |
Services and purposes
A typical config:
export const klaroConfig = {
services: [
{
name: "core",
title: "Site basics",
purposes: ["necessary"],
required: true,
},
{ name: "matomo", title: "Matomo", purposes: ["analytics"] },
{ name: "intercom", title: "Intercom", purposes: ["livechat"] },
],
};Every service answers under both its name and its title, so the gate finds
it either way:
<CookieService id="matomo">
<Matomo />
</CookieService>Klaro's purposes are free text, so they are matched on what they contain —
analytics and advertising land where you'd expect, and anything unrecognised
is treated as functional. Be explicit when that guess is wrong:
klaro({ config: klaroConfig, purposes: { livechat: "functional" } });Klaro's own purpose names are published as categories too, so a purpose that has no libconsent equivalent is still gateable:
const chat = useHasConsent("livechat");Writing consent back
Klaro is one of the few platforms where libconsent can own the UI. Leave out its own modal and render the shadcn banner instead:
<ConsentProvider adapter={klaro({ config: klaroConfig })}>
{children}
<ConsentBanner privacyPolicyUrl="/privacy" />
</ConsentProvider>A category-level answer is written through to every service under it. Services
Klaro marks required are left alone — the config author already said they are
not optional.
Google Consent Mode
Klaro does not write the Consent Mode signals, so libconsent does it — see Google Consent Mode.