---
title: ConsentProvider
description: Mount ConsentProvider at the root of a Svelte app to start c15t,
  with every prop, its default, and which options update after mount.
group: frameworks
lastModified: "2026-10-10T16:01:45+01:00"
---
## Mount the provider

Render `ConsentProvider` once, around your whole app, in the component
you pass to `mount()`:

```svelte title="src/App.svelte"
<script lang="ts">
	import { posthog } from '@c15t/integrations/posthog';
	import {
		ConsentBanner,
		ConsentDialog,
		ConsentDialogLink,
		ConsentProvider,
		manifest,
	} from '@c15t/svelte';

	const scripts = [
		posthog({
			id: 'phc_your_project_key',
			initOptions: { cookieless_mode: 'never' },
			loadMode: 'after-consent',
		}),
	];
</script>

<ConsentProvider mode={manifest()} {scripts}>
	<main>
		<h1>c15t + Svelte</h1>
		<p>Your app goes here.</p>
	</main>
	<footer>
		<ConsentDialogLink>Privacy settings</ConsentDialogLink>
	</footer>
	<ConsentBanner />
	<ConsentDialog />
</ConsentProvider>
```

`mode` is the only required prop. Here `manifest()` resolves the policy from
the snapshot the build bundled and saves choices to your Inth project, as set
up in the [quickstart](../quickstart). `manifest({ source: 'runtime' })`
fetches the manifest when the page loads instead, and `hosted()` asks the
backend's `/init`. Both read the backend URL from `consentManifest`, or take
`backendURL`. Import every mode from
`@c15t/svelte`. The consent components render inside
the provider; your app's own components can sit anywhere inside it too, so
they can call the [context getters](../getters).

In a Svelte app without SvelteKit the browser resolves the policy after the
page loads, so the banner appears after the first paint. Optional categories
stay denied until then.

## Props

Pass each option as a top-level prop, or group them in `options`. When both
set the same option, the top-level prop wins. The `ConsentManagerOptions` type
from `@c15t/svelte` lists every option. SvelteKit's `ConsentRoot` takes the
same props, except that `state` replaces `mode` and `prefetch`.

|Prop|Type|Default|Behavior|
|--|--|--|--|
|`mode`|`manifest()`, `hosted()`, `offline()` or `custom()` result, all from `@c15t/svelte`|required|Where policies come from and where choices are saved. Read once; remount the provider to change it. `ConsentRoot` builds it from `state`, or takes a `custom()` transport as `mode`.|
|`prefetch`|`ConsentState`|none|Server-resolved state, such as the result of `resolveConsent`. With a resolved policy in it, the first render already knows whether to show the banner, and the browser skips its own policy request. `ConsentRoot` passes it from `state`. Read once.|
|`scripts`|`Script[]`|none|Vendor scripts that load when their category is allowed. Updates after mount: new scripts go to the loader. See [scripts](../scripts).|
|`consentCategories`|`AllConsentNames[]`|the policy's categories|Categories the preference UI offers, within the policy's scope. Updates after mount.|
|`theme`|`Theme`|none|Slot classes and `consentActions` button styles. Design tokens in it are not applied in the browser. Updates after mount.|
|`presentation`|`ConsentPresentation`|the policy's defaults|Banner and dialog shape, position, button layout and blocking for every component. Updates after mount.|
|`legalLinks`|`LegalLinks`|none|Privacy policy, cookie policy and terms links shown in the banner and dialog. Updates after mount.|
|`i18n`|`Partial<I18nConfig>`|bundled English|Copy overrides per language. They win key by key over the backend's copy for the same language; see [translations](../translations). Read once.|
|`colorScheme`|`'light'`, `'dark'`, `'system'` or `null`|none|Toggles the `c15t-dark` class on `<html>`. `null` or unset leaves `<html>` alone. Updates after mount.|
|`noStyle`|`boolean`|`false`|Renders every component without c15t's classes. A component's own `noStyle` wins.|
|`disableAnimation`|`boolean`|follows `prefers-reduced-motion`|Turns off enter and exit transitions.|
|`scrollLock`, `trapFocus`|`boolean`|from `presentation`|Defaults for the banner and dialog. `blocking` on a component sets both.|
|`preloadDialog`|`'idle'` or `'intent'`|`'idle'`|When `ConsentDialog` starts loading before its first open. See [ConsentDialog](./consent-dialog).|
|`networkBlocker`|options or `false`|off|Holds `fetch` and XHR requests to listed domains until their category is allowed. Updates after mount: new rules and `enabled` apply, and `false` removes the blocker. The blocker loads on demand. See [network blocker](../network-blocker).|
|`iframeBlocker`|`{ disableAutomaticBlocking?: boolean }` or `false`|on|Gates iframes that carry `data-category`. Updates after mount: `false` removes the blocker and a new `disableAutomaticBlocking` rebuilds it. See [embeds](../embeds).|
|`iab`|`ProviderIABOptions` or `false`|off|IAB TCF settings. Read once. See [IAB TCF](../iab).|
|`callbacks`|`ConsentProviderCallbacks`|none|`onChoiceRecorded`, `onPermissionsChanged`, `onError` and `onBeforeConsentRevocationReload`. The latest functions are called. See [callbacks](../callbacks).|
|`reloadOnConsentRevoked`|`boolean`|`true`|Reloads the page after a save withdraws a category or vendor that was granted.|
|`overrides`|`{ country?, region?, language?, gpc? }`|none|Forces the location, language or Global Privacy Control signal the policy resolves for. A change after mount resolves the policy again.|
|`user`|`User`|none|Identity sent with the policy request and every saved choice, so the choice is linked to your user ID. A different user after mount is identified with the backend; the user you mount with is not identified separately.|
|`storageConfig`|`StorageConfig`|cookie and key `c15t`|Names and lifetime of the stored choice. Read once. On SvelteKit, pass the same name as `cookieName` to the server helpers.|
|`persistence`|`boolean` or options|`true`|`false` keeps choices in memory only. Read once.|
|`clearOnRevocation`|`ClearOnRevocationConfig`|off|Deletes first-party cookies and storage entries when their category is withdrawn. Loads on demand. See [clearing data on revocation](../clear-on-revocation). Read once.|
|`vendors`|`Vendor[]`|none|Vendors offered for vendor-level consent outside IAB. See [vendor consent](../vendor-consent). Updates after mount: a new list replaces the declared vendors.|
|`nonce`|`string`|none|Content Security Policy nonce for the `<script>` elements the script loader adds. See [Content Security Policy](../content-security-policy). Read when the loader starts.|
|`enabled`|`boolean`|`true`|`false` grants every category, hides all consent UI and skips `/init`. Updates after mount: turning it off renders a separate permissive state and keeps the visitor's stored choice for when it is turned back on.|
|`runtime`|`ConsentRuntime`|none|A runtime you created with `createConsentRuntime()`. See [share one runtime](#share-one-runtime).|
|`options`|`ConsentManagerOptions`|none|The same options as one object.|
|`children`|`Snippet`|none|Your app. The provider renders no markup of its own.|

"Read once" options are read when the provider is created. Changing them later
has no effect until the provider remounts, and outside production a change to
`mode`, `i18n` or `experiment` logs a warning. Options that update after mount
are compared with their previous values, so a new `options` object that only
changes `theme` sends no request. The provider has no `policyRules`
option. For local policy rules, pass `offline({ policyRules })` as `mode`.

## What the provider does when it mounts

The provider creates the consent runtime while the component initializes, on
the server and in the browser. Creating it has no side effects, so the server
can render the banner from `prefetch`. In the browser, `onMount` starts the
runtime:

1. It reads the stored choice from the cookie and local storage.
2. It starts the script loader, the iframe blocker and, if configured, the
   network blocker and the IAB TCF add-on.
3. It resolves the policy with its `mode`, unless `prefetch` already holds
   one.

When the provider unmounts, it stops all of them. Keep one provider at the root of the app, so it stays mounted across
navigation and every component can reach it.

With `networkBlocker`, matching requests are held from the moment the provider
is created in the browser, before its children run their own code, until the
blocker decides them.

## Share one runtime

Pass `runtime` when two component trees that cannot share Svelte context need
the same consent state. Create it with `createConsentRuntime()` from
`@c15t/svelte`, pass it to each provider, and call `runtime.start()` and
`runtime.dispose()` yourself. A provider never starts or disposes a runtime it
did not create. Options that build the runtime, such as `mode`, `scripts` and
`callbacks`, come from your `createConsentRuntime()` call; display options such
as `theme` and `noStyle` still apply per provider.

## Verify the provider

Open the page in a private window with DevTools open:

1. The banner appears once the policy resolves. `window.c15t` in the console
   shows `pkg: '@c15t/svelte'`.
2. The Network panel shows the request your mode makes: none for
   `manifest()` with a bundled snapshot, one `/init` for `hosted()`, and
   none when the page came with a server-resolved state.
3. A component that calls `getConsentManager()` renders without the
   `c15t: no v3 consent context` error.
