c15t
Version:
Headless JavaScript consent management platform for cookie banners, privacy preferences, consent storage, and script gating.
106 lines (81 loc) • 8.38 kB
Markdown
---
title: Initialization Flow
description: Reference page for initialization flow.
group: reference
---
When the consent provider mounts, it creates a cached consent runtime, reads any stored consent from the browser, fetches the resolved policy from the backend (or uses SSR/offline data), and decides whether to show the banner. This entire sequence completes before the first meaningful consent-aware render.
## Lifecycle Sequence
**Simplified**
1. **Provider mounts** — creates (or retrieves from cache) a consent runtime and store
2. **Check stored consent** — reads existing consent from cookies / localStorage; if found and the policy fingerprint hasn't changed, the banner stays hidden
3. **Fetch init data** — calls the backend `GET /init` (or uses SSR/offline data) for the resolved policy, location, and translations
4. **Apply resolved policy** — the backend resolves the policy from your [policy pack](/docs/frameworks/react/concepts/policy-packs) based on visitor geo (region → country → fallback → default). The response includes the consent model, categories, UI mode, and a material fingerprint. If no policy pack is configured, the legacy jurisdiction-to-model mapping is used instead.
5. **Decide banner visibility** — shows the banner only if no prior consent exists, the resolved policy requires it (`ui.mode` is `banner` or `dialog`), or the policy fingerprint changed since last consent
6. **Gating enforced** — scripts, iframes, and network requests tagged with a consent category are blocked until that category is granted
7. **User interacts** — choices are persisted to storage, synced to the backend (with `policySnapshotToken` if configured), and blocked scripts/iframes load immediately after consent is granted
**Sequence Diagram**
```mermaid
sequenceDiagram
participant Provider as ConsentManagerProvider
participant Store as Consent Store
participant Storage as localStorage / Cookie
participant API as c15t Backend
participant UI as Banner / Dialog
participant Scripts as Script Loader
Provider->>Store: getOrCreateConsentRuntime()
Store->>Storage: getStoredConsent()
alt Stored consent exists
Storage-->>Store: consentInfo + consents
Store->>Store: activeUI = 'none'
else No stored consent
Store->>Store: isLoadingConsentInfo = true
end
Store->>Store: initConsentManager()
Store->>Storage: Check pending consent sync
opt Pending sync from revocation reload
Store->>API: Deferred setConsent() (non-blocking)
end
alt SSR data provided
Store->>Store: tryUseSSRData()
else No SSR data
Store->>API: GET /init
API-->>Store: policy, policyDecision, location, translations
end
Store->>Store: Apply resolved policy (model, categories, ui.mode)
Store->>Store: Check fingerprint change → re-prompt if needed
Store->>Store: Set activeUI, auto-grant if opt-out/none
alt User has no prior consent or policy changed
UI->>UI: Banner / Dialog appears (per policy ui.mode)
UI->>Store: saveConsents({ type })
Store->>Storage: Persist consent + subjectId + fingerprint
Store->>Scripts: updateScripts(), updateIframes(), updateNetwork()
Store->>API: POST /subjects + policySnapshotToken (non-blocking)
end
```
## How It Works
**Mount** — When the provider renders, it creates (or retrieves from cache) a consent runtime and store. Any existing consent is read from localStorage/cookies immediately. If consent already exists and the policy fingerprint matches, the banner stays hidden and gating rules apply right away. See [Client Modes](/docs/frameworks/react/concepts/client-modes) for how the mode affects runtime creation.
**Init** — The store fetches the resolved policy, location, and translation data. In hosted mode this calls `GET /init` on your backend; in offline mode it resolves from `offlinePolicy.policyPacks` locally. If SSR data was passed to the provider, the network fetch is skipped entirely. See [Server-Side Utilities](/docs/frameworks/react/server-side) for SSR setup.
**Policy resolution** — When [policy packs](/docs/frameworks/react/concepts/policy-packs) are configured, the backend resolves the right policy for the visitor based on their geo-location (region → country → fallback → default). The resolved policy determines the consent model (`opt-in`, `opt-out`, `iab`, or `none`), which categories are in scope, and what UI to show. For `opt-out` and `none` models, all categories are auto-granted — unless the resolved policy has `consent.gpc: true` and the browser sends a Global Privacy Control signal, in which case `marketing` and `measurement` are denied. If no policy pack is configured, the legacy jurisdiction-to-model mapping is used instead. See [Consent Models](/docs/frameworks/react/concepts/consent-models) for details.
**Re-prompting** — If the resolved policy's material fingerprint differs from the fingerprint stored with the user's last consent, the banner is shown again. This happens automatically when you change consent-affecting fields (model, categories, scope mode, allowed actions). Presentation-only changes do not trigger re-prompts. See [Policy Packs — Re-Prompting](/docs/frameworks/react/concepts/policy-packs#re-prompting) for details.
**Save** — When the user interacts with the banner or dialog, their choices are persisted to localStorage/cookies and synced to the backend (along with the `policySnapshotToken` if snapshot signing is configured). Script, iframe, and network gating rules update immediately based on the new consent state. See the [Script Loader](/docs/frameworks/react/script-loader), [Iframe Blocking](/docs/frameworks/react/iframe-blocking), and [Network Blocker](/docs/frameworks/react/network-blocker) guides for gating details.
**Revocation** — If a user revokes a previously granted category, the page reloads by default to ensure a clean execution environment. The API sync is deferred to the fresh page load. See [Cookie Management](/docs/frameworks/react/concepts/cookie-management) for revocation and persistence details.
## When Does the Banner Show?
The banner appears when any of these conditions are true:
1. **No existing consent** — the user has never consented (or their consent was cleared), **and** the resolved policy requires a UI (`ui.mode` is `banner` or `dialog`, or the model is `opt-in` or `iab`)
2. **Policy changed** — the material policy fingerprint differs from the fingerprint stored with the user's last consent (re-prompting)
3. **Storage is accessible** — the browser allows localStorage (not blocked in private mode)
If the resolved model is `none` or `opt-out` (and `ui.mode` is `none`), consents are auto-granted and the banner never appears. See [Consent Models](/docs/frameworks/react/concepts/consent-models) and [Policy Packs](/docs/frameworks/react/concepts/policy-packs) for details.
## Debugging the Lifecycle
Use the DevTools panel and callbacks to inspect each step of the initialization flow. `onConsentSet` is the broad lifecycle signal; `onConsentChanged` and `subscribeToConsentChanges()` are the change-only signals for explicit post-init saves.
|Step|DevTools Panel|Callback|What to check|
|--|--|--|--|
|Init / SSR hydration|Location|`onBannerFetched`|jurisdiction, countryCode, regionCode populated?|
|Policy resolution|Policy|`onBannerFetched`|`policyId`, `matchedBy`, `fingerprint` in policyDecision|
|Model resolution|Location|`onBannerFetched`|`model` value matches the resolved policy|
|Banner visibility|Consents|—|`activeUI` in store state; does policy `ui.mode` require it?|
|Re-prompting|Policy|—|Fingerprint mismatch between stored and resolved policy?|
|Consent save|Consents + Events|`onConsentSet`|`preferences` object in callback payload|
|Change-only integrations|Events|`onConsentChanged` or `subscribeToConsentChanges()`|`allowedCategories`, `deniedCategories`, and previous values only when a real save changed preferences|
|Script loading|Scripts|`onConsentSet`|Script IDs and their load/blocked status|
|Reload on revocation|Events|`onBeforeConsentRevocationReload`|Fires before reload; check localStorage for `c15t:pending-consent-sync`|
|Deferred sync|Events|`onError` (if sync fails)|After reload, check Events panel for successful API call|