# JavaScript API



The consent runtime exposes a flat API at `window.OptinStack`. Use it to read consent state, record decisions programmatically, subscribe to changes, and delegate UI helpers to the mounted banner plugin.

## Initialization [#initialization]

Wait for the SDK to finish bootstrapping before calling API methods:

```js
await window.OptinStack.ready;
console.log(window.OptinStack.version);
```

`ready` is a Promise that resolves once the consent kernel, blocking, and plugins have initialized and the banner UI has been scheduled to load. It rejects if initialization fails. The banner plugin may register slightly after `ready` resolves; use `ui.*` helpers (which are safe no-ops until it mounts) or listen for `consent-updated` to react to user interaction.

## Consent state [#consent-state]

### `choices` [#choices]

Returns the current consent choices as an object:

```js
const choices = window.OptinStack.choices;
// { necessary: true, analytics: false, marketing: false, preferences: false }
```

Assign a full object to update multiple categories at once. `necessary` is always forced to `true`.

```js
window.OptinStack.choices = {
  necessary: true,
  analytics: true,
  marketing: false,
  preferences: false,
};
```

### Category getters and setters [#category-getters-and-setters]

Each category is available as a top-level property:

```js
window.OptinStack.necessary; // always true (read-only)
window.OptinStack.analytics; // boolean
window.OptinStack.marketing; // boolean
window.OptinStack.preferences; // boolean

window.OptinStack.analytics = true;
```

### `all` [#all]

Write-only shorthand to accept or reject all optional categories:

```js
window.OptinStack.all = true; // accept all
window.OptinStack.all = false; // reject all optional categories
```

### `acceptAll(source?)` and `rejectAll(source?)` [#acceptallsource-and-rejectallsource]

```js
window.OptinStack.acceptAll('api');
window.OptinStack.rejectAll('api');
```

The optional `source` argument is `'banner'`, `'preferences'`, or `'api'`. It is included in consent records and `consent-updated` events.

### `renew()` [#renew]

Clears stored consent, resets choices to rule defaults, and sets `hasConsented` to `false`. The banner reappears when the user has not yet consented.

```js
window.OptinStack.renew();
```

### `hasConsented` [#hasconsented]

Whether the visitor has an active stored consent record:

```js
if (window.OptinStack.hasConsented) {
  console.log('Returning visitor with saved consent');
}
```

Consent choices are also persisted in the first-party `optinstack` cookie. See [Consent Cookie](/consent-cookie) for the cookie format and subdomain sharing behavior.

## Context properties [#context-properties]

| Property        | Type      | Description                                                                          |
| --------------- | --------- | ------------------------------------------------------------------------------------ |
| `version`       | `string`  | SDK semver                                                                           |
| `gpc`           | `boolean` | Global Privacy Control detected                                                      |
| `region`        | `string`  | Detected ISO region code                                                             |
| `mode`          | `string`  | Active consent model (`opt-in`, `opt-out`, or `informational`)                       |
| `uiVariant`     | `string`  | Active banner display variant (`opt-in`, `opt-out`, `informational`, or `dont-sell`) |
| `config.site`   | `object`  | Published site configuration applied by the runtime                                  |
| `config.policy` | `object`  | Matched consent policy for the current visitor                                       |

```js
const mode = window.OptinStack.mode;
const bannerType = window.OptinStack.uiVariant;
const policy = window.OptinStack.config.policy;
```

`mode` is the consent **model** (how optional categories default and what counts as a decision). `uiVariant` is the banner **presentation**, which can be `dont-sell` while the underlying model remains `opt-out`. Prefer `uiVariant` when you need to know which UI the visitor sees.

## Server consent token [#server-consent-token]

### `getServerConsentToken()` [#getserverconsenttoken]

Returns a short-lived signed token that your backend can verify with the [`@optinstack/server`](https://www.npmjs.com/package/@optinstack/server) package. Use it when a server route should only run after the visitor has granted specific categories.

```js
await window.OptinStack.ready;

const token = await window.OptinStack.getServerConsentToken();

await fetch('/api/personalize', {
  headers: {
    'X-OptinStack-Consent': token,
  },
});
```

Behavior:

* Tokens are cached in the browser until near expiry, then refreshed automatically.
* On **opt-in** policies, the call **throws** until the visitor has stored consent (`hasConsented === true`). On **opt-out** and **informational** policies, a default token may be available before an explicit interaction.
* The token is meant for **your** backend verification. It is not a substitute for reading `OptinStack.choices` in the browser.

Verify tokens in Node with `verifyConsentToken` and `isConsentAllowed` from `@optinstack/server`. See that package's README for install and server-side examples.

## `subscribe(callback)` [#subscribecallback]

React to consent state changes. The first synchronous callback is skipped so you only receive updates after subscribing.

```js
const unsubscribe = window.OptinStack.subscribe((state) => {
  console.log(state.choices, state.mode, state.gpc);
});

// Later
unsubscribe();
```

### Keyed subscribe [#keyed-subscribe]

Subscribe to a single key:

```js
window.OptinStack.subscribe('analytics', (value) => {
  console.log('Analytics consent:', value);
});

window.OptinStack.subscribe('choices', (choices) => {
  console.log(choices);
});
```

Supported keys: `'choices'`, `'hasConsented'`, `'necessary'`, `'analytics'`, `'marketing'`, and `'preferences'`.

## `events.on()` and `events.off()` [#eventson-and-eventsoff]

Subscribe to the typed event bus. See the [Events](/events) reference for all event names and payloads.

```js
function onConsentUpdated(detail) {
  console.log(detail.choices, detail.source, detail.action);
}

window.OptinStack.events.on('consent-updated', onConsentUpdated);
window.OptinStack.events.off('consent-updated', onConsentUpdated);
```

Wildcard listener:

```js
window.OptinStack.events.on('*', (eventName, detail) => {
  console.log(eventName, detail);
});
```

Every bus event also fires as a DOM `CustomEvent` on `document.documentElement` with the `optinstack:` prefix (for example `optinstack:consent-updated`).

## `ui` [#ui]

UI helpers delegated to the mounted banner plugin. These are no-ops until the banner bundle registers.

### `ui.setPlaceholderHTML(fn)` [#uisetplaceholderhtmlfn]

Customize HTML shown inside blocked iframe placeholders when consent is denied:

```js
window.OptinStack.ui.setPlaceholderHTML((categories) => {
  return '<p>Accept consent to view this content.</p>';
});
```

### `ui.renderDeclaration(target?, options?)` [#uirenderdeclarationtarget-options]

Render the tracker declaration widget into host-page elements. Default target: `[data-optinstack-declaration]`.

```js
window.OptinStack.ui.renderDeclaration();
window.OptinStack.ui.renderDeclaration('#my-declaration', {
  styles: '.custom { color: red; }',
});
```

Returns a cleanup function, or `undefined` if the banner plugin is not mounted yet.

## Advanced [#advanced]

### `registerUiPlugin(plugin)` [#registeruipluginplugin]

Register a custom UI plugin. The production banner bundle calls this automatically. Advanced use only.

### `destroy()` [#destroy]

Tears down blocking, plugins, UI, and event listeners.

```js
window.OptinStack.destroy();
```

<Callout type="warn">
  After calling 

  `destroy()`

  , the SDK cannot be restarted without reloading the page.
</Callout>
