Introduction
Consenti is an open-source, zero-dependency Consent Management Platform (CMP). It handles the complete consent lifecycle — banner display, preference management, GPC detection, GTM / Google Consent Mode v2 integration, and compliance for GDPR, CCPA, CPRA, and ten other regulations — without pulling in a single external runtime dependency.
Two packages, one platform
| Package | Runs in | What it does |
|---|---|---|
@consenti/ui | Browser | The UI widget. Shows the consent banner and preference modal, detects GPC, fires DOM events, pushes to the GTM dataLayer, and syncs consent across tabs. Uses only browser built-ins — no framework required. |
@consenti/api | Node.js server | The backend module. Install it in your existing Node.js server — it mounts consent API routes and an admin dashboard onto your app. No separate process. Records consent to SQLite by default. Uses only Node.js built-ins. |
Frontend-only or 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 (ConsentiProfile) or inline (profileOverride) | 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 in your existing Node.js backend — mounts routes onto your server, nothing separate to run |
💡Start frontend-only. The switch to full-stack later is one config line:
api.enabled: true. Existing browser consent records remain valid until superseded by an API record.What happens on a first visit
- The widget initialises and resolves the active profile (code-defined, API-fetched, or built-in default)
- It reads any existing consent record from the browser cookie or
localStorage - If no valid record exists → the banner appears
- The user clicks Accept / Reject / Customize
- Consent is saved to the browser and (if configured) POSTed to the backend
consenti:consentSubmittedfires with the full consent record- On every subsequent visit → the banner stays hidden unless consent has expired or the profile version changed