@consentx/vanilla
v1.0.3
Published
Framework-agnostic ConsentX loader — drop-in cookie consent & CMP embed for GDPR, CCPA, DPDPA. Paste your Site Key and the widget installs itself.
Maintainers
Readme
@consentx/vanilla is a tiny (~3 KB min) loader you include with a data-site-key
attribute. It injects the self-contained ConsentX embed module into <head>,
which renders the consent banner, reads geo/config from the ConsentX server, and
emits a cx:consent event you can hook into.
This is Model C (Site Key): there is no server redirect handshake. You copy
your Site Key from the ConsentX dashboard and either drop in one <script>
tag or call the loader from code. No build step is required to use it on a plain
HTML page.
Prerequisites
- A ConsentX account: https://app.consentx.io.
- Your Site Key — dashboard → Websites → your site.
- Your site's domain on that site's allowlist (the dashboard "Add website" flow handles this). The embed only renders on allowlisted hosts.
Install
Option A — CDN / copy-paste (no build, any site)
Paste this into <head> as early as possible, on every page, and replace
YOUR_SITE_KEY:
<script type="module"
src="https://unpkg.com/@consentx/vanilla/consentx.js"
data-site-key="YOUR_SITE_KEY"></script>That's it — the loader self-initialises from data-site-key. The full
copy-paste block (with optional Google Consent Mode v2 defaults) lives in
snippet.html.
Prefer zero dependencies? You can also embed ConsentX directly without this package:
<script type="module" src="https://app.consentx.io/api/YOUR_SITE_KEY/embed.js"></script>
@consentx/vanillaadds thedata-*config, the programmatic API, the typed consent hook, and optional Consent Mode seeding on top of that.
Option B — npm (bundlers, SPAs, TypeScript)
npm install @consentx/vanilla
# or: pnpm add @consentx/vanilla / yarn add @consentx/vanillaimport ConsentX from '@consentx/vanilla';
const cx = ConsentX.load({ siteKey: 'YOUR_SITE_KEY' });Usage
Data-attribute config (Option A)
| Attribute | Required | Description |
| -------------------- | -------- | ------------------------------------------------------------------ |
| data-site-key | yes | Your Site Key from the ConsentX dashboard. |
| data-app-host | no | Override the app host (default https://app.consentx.io). |
| data-consent-mode | no | "true" / "1" to seed Google Consent Mode v2 denied-by-default. |
<script type="module"
src="https://unpkg.com/@consentx/vanilla/consentx.js"
data-site-key="YOUR_SITE_KEY"
data-consent-mode="true"></script>Programmatic API (Option B)
import ConsentX from '@consentx/vanilla';
// Inject the embed (idempotent — safe to call once).
const cx = ConsentX.load({
siteKey: 'YOUR_SITE_KEY',
appHost: 'https://app.consentx.io', // optional override
consentMode: true, // optional: seed Consent Mode v2
});
// React to consent decisions. Returns an unsubscribe function.
const off = cx.onConsent((detail) => {
console.log('granted categories:', detail.granted); // e.g. ["necessary","analytics"]
if (detail.granted.includes('analytics')) {
// load analytics now
}
});
// Reopen the preferences dialog (e.g. from a footer "Cookie settings" link).
cx.openPreferences();
// later: off();You can also subscribe without holding an instance:
import { ConsentX } from '@consentx/vanilla';
const off = ConsentX.onConsent((d) => console.log(d.granted));SPA note (React / Vue / Next / Nuxt / Svelte)
Load after hydration so the framework's DOM reconciliation does not strip
the #consentx-cookie-consent div the widget appends to <body>:
import { useEffect } from 'react';
import ConsentX from '@consentx/vanilla';
useEffect(() => {
ConsentX.load({ siteKey: 'YOUR_SITE_KEY' });
}, []);In Next.js you can instead use next/script with strategy="afterInteractive"
pointing at the CDN build, or call ConsentX.load() inside a client useEffect.
How it works
The embed module (https://app.consentx.io/api/<SITE_KEY>/embed.js) is
self-contained:
- injects the scoped widget CSS + JS,
- renders the banner into a
#consentx-cookie-consentdiv appended to<body>, - reads geo/config from the ConsentX server,
- dispatches
cx:consent(detail.granted= array of granted category slugs), - exposes
window.ConsentX(open preferences) once loaded, - auto-blocks known third-party trackers before consent.
This loader sets window.consentx_key and injects that module as a
type="module" script. With Consent Mode enabled it first seeds the
denied-by-default gtag('consent','default',...) signals; the widget then emits
the matching gtag('consent','update',...) calls on the visitor's choice.
API reference
ConsentX.load(options): ConsentX // construct + inject, returns instance
new ConsentX(options).load() // same, two steps
ConsentX.onConsent(cb): () => void // static consent subscription
instance.onConsent(cb): () => void // instance consent subscription
instance.openPreferences(): void // open the preferences dialog
instance.isLoaded: boolean // whether the embed was injected
interface ConsentXOptions {
siteKey: string; // required
appHost?: string; // default "https://app.consentx.io"
consentMode?: boolean; // default false
target?: HTMLElement | null;// default document.head
}
interface ConsentEventDetail { granted: string[]; [k: string]: unknown }Build from source
pnpm install # or npm install
pnpm run build # outputs dist/ (ESM, CJS, IIFE/CDN, .d.ts)
pnpm run demo # serves demo/ at http://localhost:4173| Output | Use |
| ------------------------ | ---------------------------------------------- |
| dist/consentx.js | ESM (import) |
| dist/consentx.cjs | CommonJS (require) |
| dist/consentx.iife.js | IIFE / CDN drop-in (window.ConsentXEmbed) |
| dist/consentx.d.ts | TypeScript declarations |
Disconnect
There is nothing stored server-side by this package. To stop the banner, remove
the snippet / stop calling ConsentX.load(). To revoke access entirely, remove
the website (or rotate the key) from the ConsentX dashboard.
