# Consenti — Full Documentation
> Open-source, GDPR-style opt-in Cookie Consent & Consent Management Platform (CMP) toolkit. Zero external runtime dependencies. Apache 2.0 license.
Consenti is a self-hosted, open-source consent toolkit built for developers — browser-first, with an optional backend for durable storage, dashboard authoring, and an audit log. It ships as two independent npm packages. It is not a hosted enterprise CMP like OneTrust or Cookiebot, which include dedicated legal/compliance teams and infrastructure Consenti does not replicate.
- Source: https://github.com/santoshe61/consenti
- npm UI: https://www.npmjs.com/package/@consenti/ui
- npm API: https://www.npmjs.com/package/@consenti/api
- Docs: https://consenti.dev/docs/getting-started/
- Summary (llms.txt): https://consenti.dev/llms.txt
---
## Packages
- `@consenti/ui` — Browser widget. Renders the consent banner and preference modal. CSS is auto-injected at runtime — no separate CSS import needed. Handles GPC signal detection, cross-tab sync via BroadcastChannel, Google Consent Mode v2, GTM integration, i18n (locale resolution), and accessibility (focus trap, ARIA roles, targeting WCAG 2.x AA).
- `@consenti/api` — Node.js backend module. Records consent to SQLite, MongoDB, PostgreSQL, or MySQL via a StorageAdapter interface. Serves a built-in Preact admin dashboard at `/consenti/`. Provides a REST API. Implements RBAC, multiple auth modes (local, OIDC, SAML), an append-only audit log (never deleted by Consenti, under any configuration), and a GDPR right-to-erasure endpoint.
- `@consenti/scanner` — Local CLI, not published to npm. Crawls a site under none/reject-all/accept-all consent states and reports undeclared third-party trackers with confidence-scored classification, fully offline.
---
## Key Technical Facts
- Runtime: Node 20+ (backend) / ES2020+ browsers (Chrome 80+, Firefox 74+, Safari 13.1+)
- UI zero external runtime deps: `document.cookie`, `BroadcastChannel`, `crypto.subtle`, `fetch`, `localStorage`
- API zero external runtime deps: `node:sqlite` (Node 22.5+), `node:crypto`, `node:fs`, `node:path`
- Build: tsup (ESM + UMD for UI; CJS + ESM for API), Turborepo monorepo, npm workspaces
- Security: IPs masked (last octet/80 bits zeroed) and salted before SHA-256 hashing, passwords via scrypt (native), JWT via HMAC-SHA256 (native), signed consent cookies using HMAC (server-side verification via `@consenti/api`'s `dataSigningHash`; standalone `@consenti/ui`-only signing is tamper-evidence, not tamper-proof — see SECURITY.md)
- User IDs: `crypto.randomUUID()` — no PII stored
- License: Apache 2.0
- Language: TypeScript strict mode throughout
---
## Compliance Coverage
Status reflects how confidently Consenti tracks ongoing legal changes, not just whether code exists — same
tiers as `ECOSYSTEM.md`. Maintained = actively tracked as the law changes. In development = supported today,
rollout still being finished. Supported = code is complete and stable, but not tracked as closely as the
Maintained tier. Partial = infrastructure provided; your own config/legal review finishes the specifics.
Routing-only = the country is mapped to a compliance-group default, but not individually legal-maintained.
| Regulation | Jurisdiction | Auto-resolves to | Status |
|---|---|---|---|
| GDPR | EU / EEA | `opt-in` | Maintained |
| UK GDPR | United Kingdom | `opt-in` | Maintained |
| CCPA / CPRA | California, USA | `opt-out-strict` | Maintained |
| VCDPA / CPA / CTDPA | Virginia, Colorado, Connecticut | `opt-out` | Maintained |
| LGPD | Brazil | `opt-in-brazil` | Maintained |
| DPDPA | India | `opt-in-dpdpa` | In development — tracking India's phased 2025-2027 rules rollout |
| PIPEDA / Law 25 | Canada / Quebec | `general-privacy-consent` (Quebec: `opt-in`) | Supported |
| POPIA | South Africa | `general-privacy-consent` | Supported |
| PDPA | Thailand | `opt-in` | Supported |
| APPI | Japan | `general-privacy-consent` | Supported |
| KVKK | Turkey | `opt-in` | Supported |
| PIPL | China | `opt-in-china` | Routing-only — UX-template routing, not individually legal-maintained |
| TCF v2.3 | IAB / Global | Vendor consent (`general-privacy-consent`) | Partial — spec-correct binary encoding needs `publisherCC` config + optional `@iabtechlabtcf/core`; simplified format otherwise. Registration only needed for programmatic/RTB ad monetization |
| GPP (US National section) | Global (programmatic, US MSPA) | n/a | Partial — spec-correct binary encoding needs optional `@iabgpp/cmpapi`; simplified format otherwise. Same registration-only-for-programmatic-ads caveat as TCF |
| COPPA | USA (children) | Age gate | Partial — age-gate widget included; parental verification requires your backend |
| GPC | Global | Signal detection | Built-in feature, not a regulation |
| Notice-only | Any | Informational | Built-in compliance group, not a regulation |
---
## Introduction
Consenti is an open-source Consent Management Platform (CMP) with zero required runtime dependencies. It handles the complete consent lifecycle — banner display, preference management, GPC detection, GTM / Google Consent Mode v2 integration, and GDPR-style opt-in flows for GDPR, CCPA, CPRA, and other regulations at varying tiers of legal currency (see Compliance Coverage above).
### Frontend-only vs Full-stack
The UI widget works entirely in the browser with no server needed. The backend is optional and adds server-side consent storage, a profile management dashboard, multi-tenant support, and audit logs.
| | Frontend-only | With backend |
|---|---|---|
| Consent storage | Browser cookie or localStorage | Server database (SQLite, MongoDB, PostgreSQL) |
| Profile management | Defined in code | Admin dashboard — no code changes to update copy |
| Consent audit log | No | Yes — every record stored with timestamp and visitor ID |
| Multi-site / multi-tenant | No | Yes |
| Setup effort | One import, one constructor call | npm install @consenti/api, mounts onto your existing server |
Tip: Start frontend-only. The switch to full-stack later is one config line: `api.enabled: true`.
### What happens on a first visit
1. The widget initialises and resolves the active profile (code-defined, API-fetched, or built-in default)
2. It reads any existing consent record from the browser cookie or localStorage
3. If no valid record exists → the banner appears
4. The user clicks Accept / Reject / Customize
5. Consent is saved to the browser and (if configured) POSTed to the backend
6. `consenti:consentSubmitted` fires with the full consent record
7. On every subsequent visit → the banner stays hidden unless consent has expired or the profile version changed
---
## UI Widget — Installation
### npm (recommended)
```bash
npm install @consenti/ui
```
Import and initialise — no CSS import needed, styles are injected automatically:
```ts
import { ConsentiSetup } from '@consenti/ui'
```
### CDN / UMD (no build step)
```html
```
### ESM in the browser (no bundler)
```html
```
### CSS options
| Approach | How |
|---|---|
| Auto-inject (default) | Nothing to do — ConsentiSetup injects a style tag on first render |
| Preload CSS (optional, avoids FOUC) | `import '@consenti/ui/dist/index.css'` in your bundler entry |
| Disable auto-inject (bring your own styles) | Set `core.disableCssTemplate: true` |
| Token overrides only | Override `--consenti-*` CSS custom properties in your stylesheet |
### Package structure
```
@consenti/ui/
├── dist/
│ ├── index.mjs ← ESM entry
│ ├── index.umd.js ← UMD entry (CDN)
│ ├── index.d.ts ← TypeScript types
│ ├── index.css ← Default styles
│ ├── react.mjs ← React hook
│ ├── vue.mjs ← Vue composable
│ └── angular.mjs ← Angular service
```
---
## UI Widget — Quick Start (Frontend Only)
```bash
npm install @consenti/ui
```
Pass an empty config and Consenti auto-detects the right compliance group from the browser's locale — GDPR for EU visitors, CCPA for California, etc.
```ts
import { ConsentiSetup } from '@consenti/ui'
// No CSS import needed — styles are auto-injected at runtime
const widget = new ConsentiSetup({
compliance: { type: 'auto' }, // geo-based: GDPR for EU, CCPA for CA, etc.
})
```
### Check consent before loading scripts
```ts
widget.onReady((consent) => {
if (consent.analytics) initAnalytics()
if (consent.marketing) initAds()
})
```
### Specific compliance mode
```ts
// GDPR opt-in
new ConsentiSetup({ compliance: { type: 'opt-in' } })
// CCPA opt-out
new ConsentiSetup({ compliance: { type: 'opt-out' } })
// TCF v2.3 — enabled server-side via @consenti/api's compliance.tcf.enabled, not a widget compliance.type value
new ConsentiSetup({ compliance: { type: 'general-privacy-consent' }, api: { enabled: true } })
```
---
## UI Widget — Quick Start (Frontend + Backend)
### Backend (Node.js / Express)
```bash
npm install @consenti/api
```
```ts
import express from 'express'
import { createConsenti } from '@consenti/api'
const app = express()
const consenti = createConsenti({
storage: { driver: 'node:sqlite', path: './consenti-data' },
auth: {
mode: 'local',
adminEmail: 'admin@example.com',
adminPassword: process.env.CONSENTI_ADMIN_PASSWORD!,
},
dashboard: true,
})
app.use(consenti.router)
app.listen(3000)
// Admin dashboard → http://localhost:3000/consenti/
```
### Frontend — connect to backend
```ts
import { ConsentiSetup } from '@consenti/ui'
const widget = new ConsentiSetup({
compliance: { type: 'auto' },
api: { enabled: true, baseUrl: 'https://your-api.example.com' },
})
```
---
## UI Widget — Framework Integrations
### React
```ts
import { useConsent } from '@consenti/ui/react'
function CookieBanner() {
const { consent, acceptAll, rejectAll } = useConsent()
return consent ? null :