React Consent API
Callbacks
Pass callbacks to the provider
Keep the callbacks in their own module:
Pass them in the ConsentProvider options, in the file that renders the
provider, such as src/consent.tsx from the
quickstart:
The provider subscribes the callbacks after it mounts, so they run in the
browser. If you render on the server, server rendering never calls them. The
provider calls the latest callbacks object it received, so a new object on
a later render takes effect without a remount. Defining the object at module
level, as above, keeps it the same across renders.
When you pass your own runtime to ConsentProvider, the provider does not
wire callbacks or reloadOnConsentRevoked from its options. Pass them to
createConsentRuntime instead.
Available callbacks
| Callback | Runs when | Receives |
|---|---|---|
onChoiceRecorded | The visitor clicks Accept All, Reject All or Save Settings, in the stock UI or through useSaveConsents(). | snapshot, the state after the choice; confirmed, the categories this action recorded; actionAt, the time as a millisecond timestamp |
onPermissionsChanged | Any effective permission changes value. | snapshot, the state after the change; previous, the permissions before it |
onError | A consent command fails, such as a failed /init request or a save the backend rejects. | error, a message string |
onBeforeConsentRevocationReload | A save withdrew a granted category or vendor, right before c15t reloads the page. | preferences, the permissions after the save |
The type for the whole object is ConsentProviderCallbacks from c15t/react.
Callbacks run after c15t updates its state, so snapshot and hooks such as
useConsent() already hold the new values.
onChoiceRecorded or onPermissionsChanged
onChoiceRecorded runs only for a visitor's action. onPermissionsChanged
runs whenever effective permissions change, whatever the cause:
| Event | onChoiceRecorded | onPermissionsChanged |
|---|---|---|
| Visitor accepts, rejects or saves | Yes | Yes, if a permission changed |
| A policy resolves and allows categories before any choice | No | Yes |
| Global Privacy Control turns off a grant | No | Yes |
| A recorded choice expires | No | Yes |
| Visitor dismisses a notice | No | No |
Use onChoiceRecorded for consent analytics and audit trails, because it
fires only when the visitor chose. Use onPermissionsChanged to start or stop
your own code. Never treat it as proof that the visitor agreed to anything,
and never save consent from it.
How consent works
explains the difference.
Dismissing a notice records no choice and changes no permission. Read it with
useNoticeDismissal() instead. For consent inside one component, use the
hooks, which re-render the component when
consent changes.
Before a revocation reload
Removing a script tag cannot stop code that already ran, so c15t reloads the
page after an accept, reject or save turns off a category or vendor that was
granted. The reload waits for the save request to finish. Right before it,
onBeforeConsentRevocationReload runs synchronously. Use it to call a
vendor's shutdown API or flush queued events. Keep it short, because the
reload does not wait for promises.
A choice that expires, a new policy and a privacy signal change permissions without a visitor action, so they do not reload the page.
To handle revocation yourself, set reloadOnConsentRevoked: false in the
provider options. Code the visitor turned off then keeps running until the
next full page load, and onBeforeConsentRevocationReload never runs.
Verify
- Add the callbacks from this page, open the console and DevTools Network, clear site data and reload under a policy that shows a banner.
- Click Accept All.
onChoiceRecordedandonPermissionsChangedboth log, and the save request to your backend appears in Network. - Reload.
onChoiceRecordeddoes not log again. - Open Privacy settings, turn off a category you allowed and save.
onBeforeConsentRevocationReloadlogs, then the page reloads. After the reload, that category's vendor requests are absent from Network.