JavaScript SDK
Reference the Probo cookie banner SDK, covering script-tag, themed, and headless installation modes, the layout API, language detection, and events.
The @probo/cookie-banner SDK is a lightweight, dependency-free JavaScript library built on Web Components. It renders the consent UI, manages visitor consent state, communicates with the Probo API, and activates third-party resources based on consent.
There are three ways to use the SDK, depending on your needs:
Script Tag (No Bundler)
Section titled “Script Tag (No Bundler)”The simplest option. Add a single <script> tag to your HTML — no build tools required:
<script src="https://unpkg.com/@probo/cookie-banner/dist/cookie-banner.iife.js" data-banner-id="YOUR_BANNER_ID" data-base-url="https://your-probo-instance.com/api/cookie-banner/v1/" data-position="bottom-left"></script>
<!-- Required: reopen control in the header or footer --><probo-settings-link>Cookie settings</probo-settings-link>This automatically renders a fully styled consent dialog. Place <probo-settings-link> in your header or footer so visitors can reopen preferences — see Settings link.
| Attribute | Required | Description |
|---|---|---|
data-banner-id |
Yes | Your banner ID from the Probo console |
data-base-url |
Yes | The Probo cookie banner API base URL |
data-position |
No | Banner card position: bottom-left (default), bottom-right, bottom-center, top-left, top-right, or top-center |
data-lang |
No | Force a specific language (e.g. "fr"). When omitted, the SDK auto-detects from the page or browser. See Language Detection. |
Themed Banner (ES Module)
Section titled “Themed Banner (ES Module)”For bundled applications (React, Vue, Svelte, Next.js, etc.), import the themed banner as an ES module:
npm install @probo/cookie-bannerRegister the component and place it in your HTML or template:
import { registerCookieBanner } from "@probo/cookie-banner";
registerCookieBanner();<probo-cookie-banner banner-id="YOUR_BANNER_ID" base-url="https://your-probo-instance.com/api/cookie-banner/v1/" position="bottom-left"></probo-cookie-banner>
<!-- Required: reopen control in the header or footer --><probo-settings-link>Cookie settings</probo-settings-link>| Attribute | Required | Description |
|---|---|---|
banner-id |
Yes | Your banner ID from the Probo console |
base-url |
Yes | The Probo cookie banner API base URL |
position |
No | Banner card position: bottom-left (default), bottom-right, bottom-center, top-left, top-right, or top-center |
lang |
No | Force a specific language (e.g. "fr"). When omitted, the SDK auto-detects from the page or browser. See Language Detection. |
Since this is a Web Component, it works in any framework. In React, JSX treats it as a custom element. In Vue or Svelte, use it directly in your template. See the React Integration guide for a complete walkthrough with a useConsent hook, Next.js setup, and TypeScript declarations.
See Theming for how to customize colors, fonts, and styling.
For programmatic access to consent state from any module (not just the DOM), see the Consent Manager API.
Headless Components (Full Control)
Section titled “Headless Components (Full Control)”For complete control over the consent UI, use the headless components. These are unstyled Web Component building blocks that you compose and style yourself:
import { registerHeadlessComponents } from "@probo/cookie-banner/headless";
registerHeadlessComponents();Then build your own layout:
<probo-cookie-banner-root banner-id="YOUR_BANNER_ID" base-url="BASE_URL"> <probo-banner> <div class="my-banner"> <p data-text="banner_description">We use cookies to improve your experience.</p> <!-- Opt-in / opt-out primary actions --> <probo-accept-button> <button>Accept all</button> </probo-accept-button> <probo-reject-button> <button>Reject all</button> </probo-reject-button> <probo-customize-button> <button>Customize</button> </probo-customize-button> <!-- Notice presentation (APPI, Mexico, unregulated): single dismiss --> <probo-acknowledge-button> <button>Got it</button> </probo-acknowledge-button> </div> </probo-banner>
<probo-preference-panel> <div class="my-preferences"> <probo-category-list> <template> <div class="category"> <span data-slot="name"></span> <span data-slot="description"></span> <probo-category-toggle> <input type="checkbox" /> </probo-category-toggle> </div> <probo-cookie-list> <template> <div class="cookie"> <span data-slot="name"></span> <span data-slot="type"></span> <span data-slot="duration"></span> </div> </template> </probo-cookie-list> </template> </probo-category-list> <probo-save-button> <button>Save preferences</button> </probo-save-button> </div> </probo-preference-panel>
<!-- CCPA only: shown when state is privacy_choices --> <probo-privacy-choices> <div class="my-privacy-choices"> <probo-reject-button> <button>Do Not Sell or Share My Personal Information</button> </probo-reject-button> </div> </probo-privacy-choices></probo-cookie-banner-root>
<!-- Required outside the root (header or footer) --><probo-settings-link>Cookie settings</probo-settings-link>Use resolveLayout / resolveBannerText to show the right buttons and copy for the active presentation (OPT_IN, OPT_OUT, or NOTICE).
Component Reference
Section titled “Component Reference”| Component | Description |
|---|---|
<probo-cookie-banner-root> |
Root element. Requires banner-id and base-url. Optional lang attribute to force a language. Manages client lifecycle and state. |
<probo-banner> |
Container for the first-layer banner card. Visibility follows layout.initial_state (closed in every opt-out jurisdiction — see Settings link). |
<probo-accept-button> |
Wraps a button that records ACCEPT_ALL consent. |
<probo-reject-button> |
Wraps a button that records REJECT_ALL consent (opt-out / Do Not Sell). |
<probo-customize-button> |
Wraps a button that opens the preference panel. |
<probo-acknowledge-button> |
Wraps a button that records ACKNOWLEDGE for NOTICE presentations (informational dismiss, currently Mexico only). Do not reuse accept-all for this. |
<probo-preference-panel> |
Container for per-category consent toggles. |
<probo-privacy-choices> |
CCPA Privacy Choices surface (sale/sharing opt-out + sensitive PI rights statement). Shown when state is privacy_choices. |
<probo-category-list> |
Renders a <template> once per cookie category. Fills data-slot="name" and data-slot="description". |
<probo-category-toggle> |
Binds the checkbox inside it to the category’s consent state. |
<probo-cookie-list> |
Renders a <template> once per cookie in the category. Fills data-slot="name", data-slot="type", and data-slot="duration". |
<probo-save-button> |
Wraps a button that saves the current preference draft. |
<probo-settings-link> |
Required header/footer reopen control. Click target comes from layout.reopen_state. See Settings link. |
Layout API
Section titled “Layout API”From 0.12 onward the API returns a structured layout on the banner config. Headless integrators should read it instead of branching on regulation or consent_mode:
import { resolveLayout, resolveBannerText,} from "@probo/cookie-banner"; // or "@probo/cookie-banner/headless"
document.addEventListener("probo-ready", (e) => { const { config } = e.detail; const layout = resolveLayout(config); // layout.presentation: "OPT_IN" | "OPT_OUT" | "NOTICE" // layout.initial_state / layout.reopen_state: "banner" | "panel" | "privacy_choices" | "hidden" // layout.buttons: which actions to show // layout.settings_link: "default" | "ccpa_privacy_choices"
const copy = resolveBannerText(config); // copy.title, copy.description, copy.primaryButton, copy.secondaryButton?});If layout is missing, the SDK logs an error and falls back to strict opt-in — that means a self-hosted Probo backend older than probod v0.246.0. Update probod when you see that warning.
Settings link
Section titled “Settings link”<probo-settings-link> is the sole reopen control. Place it in your site header or footer for every embed (script tag, themed, or headless). If it is missing, the SDK emits a soft probo-validation warning — without it visitors cannot reopen preferences.
<style> /* Style the host — typography still applies after CCPA replaces the children */ probo-settings-link { font-size: 14px; color: #334155; text-decoration: underline; }</style>
<footer> <probo-settings-link>Cookie settings</probo-settings-link></footer>Behavior by presentation / regulation (driven by layout):
| Presentation | Typical regulations | Label shown | Banner on first visit | Click opens |
|---|---|---|---|---|
| OPT_OUT (CCPA) | CCPA / CPRA, and US visitors whose state cannot be resolved | Always replaced with the statutory “Your Privacy Choices” text and official opt-out icon (English; not translated) | Closed by default | Privacy Choices panel (privacy_choices) |
| OPT_OUT (other) | Other US state laws, PIPEDA and provincial PIPA, APPI, and countries with no cookie-consent law | Your children (e.g. “Cookie settings”), or a localized fallback if empty | Closed by default | Compact opt-out banner |
| OPT_IN | GDPR, UK GDPR, FADP, Law 25, LGPD, … | Your children, or a localized fallback if empty | Open until the visitor chooses | Preference panel |
| NOTICE | LFPDPPP (Mexico) | Your children, or a localized fallback if empty | Open (informational dismiss) | Notice banner again |
Most visitors fall under OPT_OUT, where nothing opens on its own. In those jurisdictions the settings link is not a convenience — it is the visitor’s only route to their choices, so it must be present on every page. See Geolocation and regulations for the full mapping.
When a Global Privacy Control (GPC) opt-out preference signal was applied, the settings link may show a small GPC honored badge next to the label.
The themed embed mounts <probo-privacy-choices> for opt-out layouts, but reopen to that surface is CCPA-only (layout.reopen_state = privacy_choices). Other opt-out regimes reopen the compact banner. Headless integrators should include <probo-privacy-choices> when supporting CCPA. The settings link finds the banner root automatically for all three integration methods.
Style probo-settings-link itself for font size and color — not inner children. Under CCPA the SDK replaces the children, but host styles still apply. The icon keeps its statutory blue/white colors and scales with 1em.
Language Detection
Section titled “Language Detection”The SDK automatically resolves the visitor’s language using the following priority:
- Explicit attribute — The
langattribute on the component (ordata-langon the script tag) - Page language — The
langattribute on the<html>element, using the base language subtag (e.g.frfromfr-FR) - Browser language — The browser’s
navigator.language, using the base subtag - Default language — The banner’s default language configured in the console (defaults to
en)
The resolved language is sent to the API when fetching the banner configuration. The API returns all UI text, category names, and descriptions in the resolved language. If no translation exists for that language, the API falls back to the banner’s default language.
Built-in Languages
Section titled “Built-in Languages”New banners include translations for these languages out of the box:
| Code | Language | Code | Language |
|---|---|---|---|
en |
English | nl |
Dutch |
de |
German | pl |
Polish |
es |
Spanish | pt |
Portuguese |
fr |
French | tr |
Turkish |
id |
Indonesian | uk |
Ukrainian |
it |
Italian | zh |
Chinese |
ja |
Japanese | ||
ko |
Korean |
You can customize these translations and add new languages from the Probo console. All banner text is translatable, including:
- Banner title and description (including opt-out and notice variants)
- Button labels (accept all, reject all, customize, save, dismiss / acknowledge)
- Preference panel title and description
- Cookie detail labels (type, description, duration)
- ARIA accessibility labels
- Privacy policy / cookie policy link text
- Content placeholder text (shown when resources are blocked)
- Duration labels (years, months, days, persistent, etc.)
Forcing a Language
Section titled “Forcing a Language”To override auto-detection, set the language explicitly:
Script tag:
<script src="https://unpkg.com/@probo/cookie-banner/dist/cookie-banner.iife.js" data-banner-id="YOUR_BANNER_ID" data-base-url="https://your-probo-instance.com/api/cookie-banner/v1/" data-lang="de"></script>Themed banner:
<probo-cookie-banner banner-id="YOUR_BANNER_ID" base-url="https://your-probo-instance.com/api/cookie-banner/v1/" lang="de"></probo-cookie-banner>Headless components:
<probo-cookie-banner-root banner-id="YOUR_BANNER_ID" base-url="https://your-probo-instance.com/api/cookie-banner/v1/" lang="de"> <!-- ... --></probo-cookie-banner-root>Matching the Page Language
Section titled “Matching the Page Language”In most cases, you don’t need to set a language explicitly. If your page has a lang attribute on the <html> element, the SDK picks it up automatically:
<html lang="fr"></html>This is the recommended approach for multilingual sites that already set the lang attribute as part of their i18n setup.
Events
Section titled “Events”The SDK emits custom events that bubble through the DOM. Listen on the root element or any ancestor:
| Event | Detail | Description |
|---|---|---|
probo-ready |
{ config, gpcApplied, regulation } |
Fired when the banner configuration has been loaded. config includes language, default_language, texts, layout, consent_mode, regulation, cookie_policy_url, and categories. gpcApplied is true if a GPC opt-out was applied. |
probo-state |
{ state, prev } |
Fired when the banner UI state changes. States: loading, banner, panel, privacy_choices, hidden. |
probo-consent |
{ action, consent_data } |
Fired after consent is recorded. Actions: ACCEPT_ALL, REJECT_ALL, CUSTOMIZE, GPC, ACKNOWLEDGE. |
probo-validation |
{ missing } |
Soft composition warning (e.g. missing <probo-settings-link>). Does not block load. |
document.addEventListener("probo-consent", (e) => { console.log("Consent action:", e.detail.action);});How Consent Is Stored
Section titled “How Consent Is Stored”- Client-side: A
probo_consentcookie stores the visitor’s consent state. The cookie’smax-ageis set to the consent expiry configured on the banner (in days). It usesSameSite=Lax. - Server-side: Every consent action is recorded via the Probo API with the banner version, visitor ID, action type, anonymized IP address, and user agent. IP addresses are anonymized before storage (IPv4 last octet zeroed, IPv6 masked to /48) — the full IP is never persisted. See Audit Trail for the complete list of stored fields.
- Visitor identity: The SDK generates a random visitor ID and stores it in
localStorage. This ID is used to look up existing consent when the visitor returns. - Offline resilience: If the API is unreachable when consent is recorded, the request is queued in
localStorageand retried automatically on the next page load.
Integrations
Section titled “Integrations”The SDK ships with built-in integrations that automatically sync consent state with third-party services. Integrations are enabled by default — they activate only when the corresponding flags are configured on your cookie categories in the Probo console. No extra code is needed.
Google Consent Mode
Section titled “Google Consent Mode”The SDK pushes Google Consent Mode v2 signals to gtag() or dataLayer, keeping Google tags in sync with visitor consent.
How it works:
- On load, the SDK sends a
consent("default", ...)call that sets all configured consent types to"denied". - When the visitor makes a choice, the SDK sends a
consent("update", ...)call with"granted"or"denied"for each consent type based on the visitor’s per-category choices.
Configuration is driven by the GCM consent types field on each cookie category in the Probo console. Map categories to Google consent types like analytics_storage, ad_storage, ad_user_data, or ad_personalization. Categories without GCM consent types configured are ignored.
The integration detects window.gtag or window.dataLayer automatically. If neither is present, it does nothing.
PostHog
Section titled “PostHog”PostHog isn’t auto-synced by the SDK — but the Consent Manager API gives you everything you need to wire it up in a few lines and stay compliant with GDPR, CCPA, and the other regulations the banner handles.
See the dedicated guides:
- How to set up PostHog: GDPR, CCPA, and global privacy laws — cookieless-only vs consent-aware setup, with a minimum working example for each.
- PostHog feature flags behind a cookie banner — evaluate flags only after analytics consent and
identify(), and why Track 2 should always usecookieless_mode: "on_reject".
A complete working integration (including a consent-gated feature flag demo) lives in the cookie-banner-react example.