How Auto-Detection Works
Consenti can automatically show the right banner for each visitor's jurisdiction — GDPR for EU visitors, CCPA for Californians, LGPD for Brazilians — without you writing any geo-detection code. This guide explains the three resolution scenarios and when to use each.
The three scenarios
Which scenario runs depends on two settings: whether api.enabled is true, and what compliance.type is set to.
| Scenario | api.enabled | compliance.type | How it resolves |
|---|---|---|---|
| 1A | false | 'auto' | Browser timezone + navigator.language → compliance group → pre-built profile |
| 1B | false | fixed group ID | Loads the matching pre-built profile directly — no geo-detection at all |
| 2A | true | 'auto' | GET /resolve-profile?tz&lang&locale → backend geo-resolves → returns profile URL |
Scenario 1A — Client-side auto (no backend)
This is the default when you omit the api config entirely. The widget reads two browser signals:
Intl.DateTimeFormat().resolvedOptions().timeZone— e.g.Europe/Parisnavigator.language— e.g.fr-FR
These are matched against an embedded 190+ country map to derive a compliance group. A visitor with timezone Europe/Paris gets the opt-in (GDPR) group. A visitor with timezone America/Los_Angeles gets opt-out (CCPA).
// Scenario 1A — fully client-side, zero network calls except the profile chunk
new ConsentiSetup({
// compliance.type defaults to 'auto' when omitted
// api defaults to { enabled: false }
})Scenario 1B — Fixed compliance group
When you want the same regulation for every visitor (e.g. you only serve EU users, or you want to apply GDPR globally as the strictest baseline), set compliance.type to a specific group ID. No geo-detection happens at all.
new ConsentiSetup({ compliance: { type: 'opt-in' } })Scenario 2A — Server-side geo-resolution
When you have a Consenti backend running, the widget delegates geo-resolution entirely to the server. This is more accurate because your backend can use real IP geolocation (MaxMind, geoip-lite, ipinfo.io) rather than relying on timezone heuristics.
On page load the widget sends one request, with timezone/language/locale hints base64-encoded into a single data query param:
GET /consenti/api/v1/resolve-profile?data=eyJ0aW1lem9uZSI6IkV1cm9wZS9QYXJpcyIsImxhbmd1YWdlIjoiZnItRlIiLCJsb2NhbGUiOiJmci1GUiJ9The backend responds with:
{
"path": "/consenti/api/v1/profiles/default/opt-in/fr-FR",
"locale": "fr-FR",
"complianceGroup": "opt-in",
"found": true
}The widget then fetches the profile JSON directly from the returned path. This second request is served from disk (zero DB) and is CDN-cacheable.
// Scenario 2A — server geo-resolves the compliance group
new ConsentiSetup({
api: {
enabled: true,
baseUrl: 'https://consent.example.com',
},
compliance: { type: 'auto' },
})/resolve-profile response is cached in sessionStorage for up to 60 minutes per tab — repeat page navigations within that window never re-fetch it. Once a visitor has an existing consent decision, their compliance group is also read directly from their consent cookie on every later visit — including a brand new tab or a new day — so /resolve-profile is skipped entirely from then on, not just within one session.The 8 built-in compliance groups
| Group ID | Region / Law | Model | GPC default |
|---|---|---|---|
| opt-in | EU / EEA — GDPR | Opt-in | honor |
| opt-out | California — CCPA | Opt-out | honor |
| opt-out-strict | California — CPRA | Strict opt-out | strict |
| opt-in-dpdpa | India — DPDPA | Opt-in | honor |
| opt-in-china | China — PIPL | Opt-in | ignore |
| opt-in-brazil | Brazil — LGPD | Opt-in | honor |
| general-privacy-consent | Global / general | Opt-in | honor |
| notice-only | Informational | Notice | ignore |