---
title: Policy Packs
description: Configure regional consent policies in React — hosted mode, presets, and offline fallback.
---
Policy packs configure how c15t handles regional consent — which model (opt-in, opt-out, none), which categories, and what UI to show. The backend resolves the right policy automatically based on the visitor's location.

**For most apps, you just need a `ConsentManagerProvider` pointing at your backend with presets configured there.** The frontend receives the resolved policy via the `/init` response — no client-side policy config required.

When a backend isn't available — local development, static previews, Storybook, automated tests, or as a resilience fallback during a temporary outage — you can pass policies directly to the provider via `offlinePolicy.policyPacks` and c15t resolves them locally.

> ℹ️ **Info:**
> For QA and testing, use the c15t DevTools to simulate different regions and policy responses against your real backend, rather than switching to offline mode.

## Hosted Mode (Recommended)

When using inth.com or a self-hosted backend, the provider connects automatically. No policy configuration is needed on the frontend:

```tsx
<ConsentManagerProvider
  options={{
    backendURL: 'https://your-instance.c15t.dev',
  }}
>
  <ConsentBanner />
  <ConsentDialog />
  {children}
</ConsentManagerProvider>
```

The backend resolves the correct policy based on the visitor's geo data and returns it in the `/init` response. Configure your presets on the backend side.

## Offline Presets (Development and Fallback)

Use offline presets mainly for local development, Storybook, deterministic tests, or temporary backend outages:

```tsx
import { policyPackPresets } from '@c15t/react';

offlinePolicy: {
  i18n: {
    defaultProfile: 'default',
    messages: {
      default: {
        translations: {
          en: { cookieBanner: { title: 'Privacy choices' } },
        },
      },
      eu: {
        fallbackLanguage: 'en',
        translations: {
          en: { cookieBanner: { title: 'EU GDPR Consent' } },
          fr: { cookieBanner: { title: 'Consentement RGPD' } },
          de: { cookieBanner: { title: 'GDPR-Einwilligung' } },
        },
      },
    },
  },
  policyPacks: [
    {
      ...policyPackPresets.europeOptIn(),
      i18n: { messageProfile: 'eu' },
    },
    policyPackPresets.californiaOptOut(),
    policyPackPresets.worldNoBanner(),
  ],
}
```

Available presets:

| Preset               | Model     | Matches                                     |
| -------------------- | --------- | ------------------------------------------- |
| `europeOptIn()`      | `opt-in`  | EEA + UK countries + geo fallback           |
| `europeIab()`        | `iab`     | EEA + UK countries + geo fallback (TCF 2.3) |
| `californiaOptOut()` | `opt-out` | US-CA region                                |
| `quebecOptIn()`      | `opt-in`  | CA-QC region                                |
| `worldNoBanner()`    | `none`    | default fallback                            |

## React Example (Hosted)

Point the provider at your backend — policy resolution happens server-side:

```tsx
import type { ReactNode } from 'react';
import {
  ConsentBanner,
  ConsentDialog,
  ConsentManagerProvider,
} from '@c15t/react';

export function ConsentManager({ children }: { children: ReactNode }) {
  return (
    <ConsentManagerProvider
      options={{
        backendURL: 'https://your-instance.c15t.dev',
      }}
    >
      <ConsentBanner />
      <ConsentDialog />
      {children}
    </ConsentManagerProvider>
  );
}
```

## Offline / Fallback

For local development, previews, automated tests, or when the backend is temporarily unreachable, pass policies directly:

```tsx
import type { ReactNode } from 'react';
import {
  ConsentBanner,
  ConsentDialog,
  ConsentManagerProvider,
  policyPackPresets,
} from '@c15t/react';

export function ConsentManager({ children }: { children: ReactNode }) {
  return (
    <ConsentManagerProvider
      options={{
        mode: 'offline',
        offlinePolicy: {
          policyPacks: [
            policyPackPresets.europeOptIn(),
            policyPackPresets.californiaOptOut(),
            policyPackPresets.worldNoBanner(),
          ],
        },
        overrides: {
          country: 'DE', // Preview as a German visitor
        },
      }}
    >
      <ConsentBanner />
      <ConsentDialog />
      {children}
    </ConsentManagerProvider>
  );
}
```

## Provider Shape

Configure packs through `offlinePolicy.policyPacks`. Add `offlinePolicy.i18n`
when you want local previews or fallback behavior to mirror hosted policy-profile language behavior:

```tsx
<ConsentManagerProvider
  options={{
    mode: 'offline',
    offlinePolicy: {
      i18n: {
        defaultProfile: 'default',
        messages: {
          default: {
            translations: {
              en: { cookieBanner: { title: 'Privacy choices' } },
            },
          },
          qc: {
            fallbackLanguage: 'fr',
            translations: {
              en: { cookieBanner: { title: 'Quebec Privacy Settings' } },
              fr: { cookieBanner: { title: 'Paramètres de confidentialité du Québec' } },
            },
          },
        },
      },
      policyPacks: [
        {
          id: 'qc_opt_in',
          match: { regions: [{ country: 'CA', region: 'QC' }] },
          i18n: { messageProfile: 'qc' },
          consent: { model: 'opt-in', expiryDays: 365 },
          ui: { mode: 'banner' },
        },
        {
          id: 'default',
          match: { isDefault: true },
          consent: { model: 'none' },
          ui: { mode: 'none' },
        },
      ],
    },
    overrides: { country: 'CA', region: 'QC' },
  }}
>
```

With that setup, offline mode resolves language the same way as hosted mode:

* the active policy profile defines the allowed language set
* each profile can define its own `fallbackLanguage`
* built-in translations only fill missing keys for the selected language

## Fallback Behavior

| Configuration                        | Result                                                                   |
| ------------------------------------ | ------------------------------------------------------------------------ |
| `offlinePolicy.policyPacks` omitted  | Synthetic opt-in fallback banner (also used for hosted network fallback) |
| `offlinePolicy: { policyPacks: [] }` | Explicit no-banner mode                                                  |
| Non-empty pack, no match, no default | Explicit no-banner mode                                                  |

Omitting the option gives you a safe opt-in default for local development and outage scenarios. Providing it tells c15t you want deterministic preview or fallback behavior exactly as configured.

## QA and Debugging

The best way to test regional consent behavior is with the [c15t DevTools](/docs/frameworks/react/dev-tools). The DevTools Policy panel lets you simulate different countries, regions, and GPC signals against your real backend — no code changes needed.

For deeper inspection:

* Read `policy` and `policyDecision` from `useConsentManager()` to see the resolved config
* Open the DevTools Policy panel to inspect matcher resolution and fingerprints
* Compare your frontend preview with the backend `/init` response before shipping

If you need fully deterministic resolution without a backend during testing or preview work (for example, in automated tests or Storybook), pair `offlinePolicy.policyPacks` with `overrides`:

```tsx
options={{
  mode: 'offline',
  offlinePolicy: {
    policyPacks: [
      policyPackPresets.europeOptIn(),
      policyPackPresets.californiaOptOut(),
      policyPackPresets.worldNoBanner(),
    ],
  },
  overrides: {
    country: 'US',
    region: 'CA',
    language: 'en-US',
    gpc: true, // Simulate Global Privacy Control
  },
}}
```

> ℹ️ **Info:**
> For the full concept model (matchers, scope modes, re-prompting), see Policy Packs concepts. For backend setup, see the self-host guide.
