---
title: Quickstart
description: Get started with c15t in vanilla JavaScript — framework-agnostic consent management with no UI dependencies.
---
## Installation

| Package manager | Command            |
| :-------------- | :----------------- |
| npm             | `npm install c15t` |
| pnpm            | `pnpm add c15t`    |
| yarn            | `yarn add c15t`    |
| bun             | `bun add c15t`     |

## Initialize the Runtime

`getOrCreateConsentRuntime()` creates a consent client and a Zustand vanilla store in a single call. The store holds all consent state and exposes methods for checking, setting, and subscribing to consent changes.

```ts
import { getOrCreateConsentRuntime } from 'c15t';

const { consentManager, consentStore } = getOrCreateConsentRuntime({
  mode: 'hosted',
  backendURL: 'https://your-instance.c15t.dev',
  consentCategories: ['necessary', 'measurement', 'marketing'],
});
```

> ℹ️ **Info:**
> Hosted mode is the recommended production setup because the backend resolves jurisdiction and translations, stores consent decisions outside the current browser, and can re-sync after temporary outages.
>
> ℹ️ **Info:**
> You can switch to mode: 'offline' for local-only storage, demos, or static previews, but that removes backend audit history, automatic jurisdiction detection, and server-side consent awareness. Review Client Modes before using offline mode in production.

## Subscribe to State Changes

The store is a [Zustand vanilla store](https://zustand.docs.pmnd.rs/guides/extracting-actions). Use `subscribe()` for UI and general state updates, `subscribeToConsentChanges()` for change-only consent integrations, and `getState()` to read the current state:

```ts
// React to every state change
consentStore.subscribe((state) => {
  console.log('Consent state:', state.consents);
  console.log('Show banner?', state.activeUI === 'banner');
});

// React only to real saved preference changes
consentStore
  .getState()
  .subscribeToConsentChanges(({ allowedCategories, deniedCategories }) => {
    analytics.syncConsent({ allowedCategories, deniedCategories });
  });

// Read current state at any time
const state = consentStore.getState();
console.log('Has measurement consent:', state.has('measurement'));
```

## Check and Set Consent

```ts
const state = consentStore.getState();

// Check if a category has consent
if (state.has('measurement')) {
  // Safe to load analytics
}

// Accept all categories
await state.saveConsents('all');

// Accept only necessary categories
await state.saveConsents('necessary');

// Set a specific category
state.setConsent('marketing', true);
```

## Minimal Consent Prompt

Here's a bare-bones example using the store to drive a consent prompt — no framework required:

```ts
import { getOrCreateConsentRuntime } from 'c15t';

const { consentStore } = getOrCreateConsentRuntime({
  mode: 'hosted',
  backendURL: 'https://your-instance.c15t.dev',
  consentCategories: ['necessary', 'measurement', 'marketing'],
});

// Subscribe to show/hide the banner
consentStore.subscribe((state) => {
  const banner = document.getElementById('consent-banner');
  if (banner) {
    banner.style.display = state.activeUI === 'banner' ? 'block' : 'none';
  }
});

// Wire up buttons
document.getElementById('accept-all')?.addEventListener('click', () => {
  consentStore.getState().saveConsents('all');
});

document.getElementById('reject')?.addEventListener('click', () => {
  consentStore.getState().saveConsents('necessary');
});
```

## Verify It Works

Open the browser console and inspect the store state:

```ts
// The store is also available on the window object
const state = window.c15tStore?.getState();
console.log('Consents:', state?.consents);
console.log('Has consented:', state?.hasConsented());
console.log('Location:', state?.locationInfo);
```

> ℹ️ **Info:**
> No UI included — the c15t core package is fully headless. See Building UI for creating your own components, or use @c15t/react / @c15t/nextjs for pre-built UI.

## Optional: Install Agent Skills

Install c15t agent skills to let AI agents help with styling, i18n, scripts & other configuration.

| Package manager | Command                     |
| :-------------- | :-------------------------- |
| npm             | `npx @c15t/cli skills`      |
| pnpm            | `pnpm dlx @c15t/cli skills` |
| yarn            | `yarn dlx @c15t/cli skills` |
| bun             | `bunx @c15t/cli skills`     |

See [AI Agents](/docs/ai-agents) for bundled package docs and agent skills.

## Next Steps

* [Client Modes](/docs/frameworks/javascript/concepts/client-modes) — Choose between hosted, offline, or custom backend
* [Store API](/docs/frameworks/javascript/api/overview) — Full reference for store state and actions
* [Script Loader](/docs/frameworks/javascript/script-loader) — Gate third-party scripts behind consent
* [Building UI](/docs/frameworks/javascript/building-ui) — Create your own consent components
* [AI Agents](/docs/ai-agents) — Get bundled package docs and reusable agent skills for c15t
