---
title: Client Modes
description: Choose how c15t connects to its backend - full hosted integration, offline-only, or bring your own backend.
---
c15t supports three client modes that determine how consent data is stored and synchronized. Choose the mode that matches your infrastructure:

* **Hosted mode** - Recommended for production. Backend-backed consent with geolocation, centralized policy resolution, audit history, and offline fallback.
* **Offline mode** - Browser-only storage with no network requests. Best for local development, demos, static deployments, or controlled fallback scenarios.
* **Custom mode** - Bring your own backend with custom endpoint handlers

> ℹ️ **Info:**
> If you need durable consent records, server-side enforcement, or automatic jurisdiction detection, use hosted mode. Offline mode cannot provide those guarantees because consent lives only in the browser.

<span id="c15t-mode" />

## Hosted Mode (Recommended)

The default mode. Connects to a c15t backend for full consent lifecycle management. We recommend using [inth.com](https://inth.com) for a fully managed experience, but you can [self-host](/docs/self-host) as well.

> ℹ️ **Info:**
> mode: 'hosted' is the preferred value. The legacy alias mode: 'c15t' is still supported for backward compatibility.

**What happens:**

1. On page load, the client calls `/init` to fetch geolocation, jurisdiction, localized translation strings
2. When the user grants or changes consent, it is saved locally before being synced to the backend.
3. If the backend is unreachable, it falls back to Offline mode and re-syncs with the backend when it's available

**Configuration:**

* `backendURL` (required) - API endpoint path

**Why it is the default for production:**

* The backend stays the source of truth for policy, translations, and jurisdiction logic
* Consent decisions can be stored beyond the current browser session for audit and support workflows
* Server-side systems can preload consent-aware behavior instead of waiting for client-only storage
* If the backend is temporarily unavailable, c15t can fall back locally and re-sync later

**Best for:** Production apps that need geolocation-based jurisdiction detection, consent record storage, and compliance audit trails.

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

export function ConsentManager({ children }: { children: ReactNode }) {
  return (
    <ConsentManagerProvider
      options={{
        mode: 'hosted',
        backendURL: '/api/c15t',
      }}
    >
      <ConsentBanner />
      {children}
    </ConsentManagerProvider>
  );
}
```

## Offline Mode

No network requests. Consent is stored entirely in the browser using localStorage and cookies.

**What happens:**

1. Default jurisdiction is GDPR unless manually set via `overrides`
2. Consent preferences persist locally only
3. No server-side consent records or analytics

> ℹ️ **Info:**
> Important: Offline mode still stores consent locally (cookie + localStorage). It only skips backend storage and sync.

### Consequences of Browser-Only Storage

If consent is not stored at all (for example, storage is blocked or frequently cleared):

* Users are treated as new visitors and must re-consent repeatedly
* Preferences are lost across browser resets, private sessions, and device changes
* You have no reliable audit evidence to prove prior consent choices
* Support and compliance teams have no centralized visibility into consent history by default
* Server-side systems cannot apply prior consent decisions before client initialization

**Trade-offs:**

* No automatic geolocation or jurisdiction detection
* No consent audit trail
* No centralized policy or translation updates without shipping frontend changes
* No cross-device sync
* No server-side visibility before client initialization
* Works without any backend infrastructure

**Best for:** Local development, Storybook/static demos, resilience fallback, or simpler sites that explicitly accept browser-only consent storage.

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

export function ConsentManager({ children }: { children: ReactNode }) {
  return (
    <ConsentManagerProvider
      options={{
        mode: 'offline',
        overrides: {
          country: 'DE', // Override country to trigger GDPR jurisdiction
        },
      }}
    >
      <ConsentBanner />
      {children}
    </ConsentManagerProvider>
  );
}
```

## Custom Mode

Bring your own backend. You provide handler functions for each consent endpoint, and c15t calls them instead of making HTTP requests.

**What happens:**

1. On page load, the client calls your endpoint handler to fetch geolocation, jurisdiction, localized translation strings
2. When the user grants or changes consent, it is saved locally before being synced to the backend.
3. If one of your handlers fails, c15t returns a handler error and keeps local consent state, but automatic offline fallback and retry queue behavior is not provided for custom handlers by default

This lets you integrate c15t with any existing API - your CRM, your own consent database, or a third-party compliance service.

**Best for:** Teams with existing consent infrastructure that want c15t's frontend without its backend.

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

export function ConsentManager({ children }: { children: ReactNode }) {
  return (
    <ConsentManagerProvider
      options={{
        mode: 'custom',
        endpointHandlers: {
          async init() {
            const res = await fetch('/my-api/consent/init');
            const data = await res.json();
            return { data, response: res, error: null };
          },
          async setConsent(options) {
            const res = await fetch('/my-api/consent', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify(options?.body),
            });
            return { data: await res.json(), response: res, error: null };
          },
        },
      }}
    >
      <ConsentBanner />
      {children}
    </ConsentManagerProvider>
  );
}
```

## Choosing a Mode

| Feature                       | Hosted          | Offline                   | Custom              |
| ----------------------------- | --------------- | ------------------------- | ------------------- |
| Geolocation                   | Automatic       | Manual via overrides      | Your implementation |
| Policy source of truth        | Backend-managed | Bundled into the frontend | Your implementation |
| Consent sync                  | API             | Local only                | Your implementation |
| Audit trail                   | Backend records | Not available             | Your implementation |
| Server-side consent awareness | Supported       | Not available             | Your implementation |
| SSR data                      | Supported       | Not available             | Your implementation |
| Analytics                     | Built-in        | Not available             | Your implementation |
| Infrastructure                | c15t backend    | None                      | Your backend        |
| Setup effort                  | Minimal         | Zero                      | Moderate            |
