---
title: Callbacks
description: Run code in a Vue app when a visitor records a consent choice, when
  permissions change, before a revocation reload, and when c15t reports an
  error.
group: frameworks
lastModified: "2026-10-10T16:01:45+01:00"
---
## Register callbacks

Pass `callbacks` to the plugin. Keep them in their own file:

```ts title="src/consent-callbacks.ts"
import type { C15tVuePluginOptions } from 'c15t/vue/vue-plugin';

export const callbacks = {
	// The visitor clicked Accept all, Reject all or Save.
	onChoiceRecorded: ({ snapshot }) => {
		console.info('Choice recorded', snapshot.explicitChoice);
	},
	onError: ({ error }) => {
		console.error('c15t', error);
	},
	// Permissions changed for any reason: a choice, an expired choice, a new
	// policy or a privacy signal.
	onPermissionsChanged: ({ previous, snapshot }) => {
		console.info('Permissions', previous, snapshot.effectivePermissions);
	},
} satisfies NonNullable<C15tVuePluginOptions['callbacks']>;
```

Then add them to the plugin options in `src/main.ts`:

```ts title="src/main.ts"
app.use(c15tVue, { callbacks, mode: manifest(), scripts });
```

c15t wires the callbacks once for the app, when the plugin installs. A
component does not need to be mounted for them to run.

## Available callbacks

|Callback|Runs when|Receives|
|--|--|--|
|`onChoiceRecorded`|The visitor clicks Accept All, Reject All or Save Settings, in the stock UI or through `useConsentSave()`.|`snapshot`, `confirmed` (the categories the action covered) and `actionAt`|
|`onPermissionsChanged`|Any effective permission changes value.|`snapshot` and `previous`, the permissions before the change|
|`onBeforeConsentRevocationReload`|A save withdraws a granted category or vendor, right before c15t reloads the page.|`preferences`, the permissions after the save|
|`onError`|A consent command fails, for example a save the backend rejects.|`error`, a message string|

## onChoiceRecorded or onPermissionsChanged

`onChoiceRecorded` fires only for a visitor's action. Use it to count consent
decisions or to send the choice to your own analytics.

`onPermissionsChanged` also fires when a stored choice expires, when a new
policy applies, and when a privacy signal such as Global Privacy Control
changes, with no action from the visitor. Use it to start or stop code
that depends on a permission. Do not treat it as evidence that the visitor
chose anything.

Dismissing a notice fires neither callback, because it records no choice and
changes no permission. Subscribe to it with
`useConsentKernel().events.on('notice:dismissed', listener)`.
[How consent works](/docs/concepts/how-consent-works#a-permission-is-not-a-recorded-choice)
explains the difference.

## Before a revocation reload

Removing a script tag cannot stop code that already ran, so c15t reloads the
page after a save withdraws a granted category or vendor.
`onBeforeConsentRevocationReload` runs synchronously right before that. Use
it to call a vendor's shutdown API. Avoid long work, because the reload does
not wait. Set `reloadOnConsentRevoked: false` to handle revocation yourself.

## Callbacks with a shared runtime

When you pass `runtime` to the plugin, the plugin ignores `callbacks`. Register
them where you create the runtime.

## Verify

Open the console, load the app and click **Accept All**. `onChoiceRecorded` logs
once and `onPermissionsChanged` logs the new permissions. Reload: neither logs
a new choice. Withdraw a category in preferences and save, and the
revocation callback runs before the page reloads.
