# Banner Control



The consent banner and preferences dialog are rendered by the banner UI plugin inside a Shadow DOM. There is no `ui.show()` or `ui.hide()` API. Use the consent API and DOM events below to interact with the banner programmatically.

## Open preferences [#open-preferences]

Dispatch a DOM event that the banner plugin listens for:

```html
<a href="#" id="manage-consent">Consent preferences</a>

<script>
  document.getElementById('manage-consent').addEventListener('click', (e) => {
    e.preventDefault();
    window.dispatchEvent(new CustomEvent('optinstack:open-preferences', { bubbles: true }));
  });
</script>
```

Wait for the SDK before dispatching if your script runs early:

```js
await window.OptinStack.ready;
window.dispatchEvent(new CustomEvent('optinstack:open-preferences', { bubbles: true }));
```

The event opens the preferences dialog for consent variants that include preferences. Informational banners do not have a preferences dialog, so the event is ignored for that variant.

## Reset consent and re-prompt [#reset-consent-and-re-prompt]

Call `renew()` to clear stored consent and reset choices to rule defaults. When `hasConsented` becomes `false`, the banner appears again for visitors who had previously consented.

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

Use this for "Change consent" links or consent expiry flows configured in the dashboard.

## Record consent from custom UI [#record-consent-from-custom-ui]

Build your own accept/reject buttons and record decisions through the JavaScript API. The runtime handles script unblocking, persistence, consent record reporting, and Google Consent Mode updates automatically.

```js
// Custom "Accept all" button
document.getElementById('my-accept-btn').addEventListener('click', () => {
  window.OptinStack.acceptAll('api');
});

// Custom partial consent
document.getElementById('my-analytics-btn').addEventListener('click', () => {
  window.OptinStack.choices = {
    necessary: true,
    analytics: true,
    marketing: false,
    preferences: false,
  };
});
```

<Callout type="info">
  Pass `'api'` as the source when recording consent from your own UI so consent records reflect the origin correctly.
</Callout>

## Check consent before showing content [#check-consent-before-showing-content]

Gate custom content on consent state:

```js
await window.OptinStack.ready;

function updateContent() {
  const showAnalytics = window.OptinStack.analytics;
  document.getElementById('analytics-section').hidden = !showAnalytics;
}

window.OptinStack.subscribe(updateContent);
updateContent();
```

## Blocked iframe placeholders [#blocked-iframe-placeholders]

When an iframe is blocked, the runtime shows a placeholder inside the iframe. Customize its HTML with `ui.setPlaceholderHTML()`:

```js
window.OptinStack.ui.setPlaceholderHTML((categories) => {
  return '<button id="accept">Accept to view</button>';
});
```

Return trusted HTML only. If your placeholder includes dynamic text, escape it before building the string.

From inside the placeholder (same origin as the iframe document), you can post a message to the parent page:

```js
// Accept all consent from inside a blocked iframe placeholder
parent.postMessage({ type: 'optinstack:action', action: 'acceptAll' }, '*');

// Open preferences from inside a blocked iframe placeholder
parent.postMessage({ type: 'optinstack:action', action: 'openPreferences' }, '*');
```

These messages are only accepted from OptinStack-controlled iframes.

## Tracker declaration widget [#tracker-declaration-widget]

Render the tracker declaration list on your page (cookie / tracker inventory for the current project):

```html
<div data-optinstack-declaration></div>
```

```js
await window.OptinStack.ready;
window.OptinStack.ui.renderDeclaration();
```

Or target a specific element:

```js
window.OptinStack.ui.renderDeclaration('#my-declaration', {
  styles: '.os-cookie-declaration { --os-decl-link-color: #047857; }',
});
```

The widget is filled from your **published tracker inventory** and providers, reflects the visitor's current choices, and can open preferences or withdraw optional consent when the banner UI supports it. If the banner plugin has not mounted yet, `renderDeclaration` returns `undefined`; wait for `ready` and retry or re-call after navigation.

See the [JavaScript API](/api#ui) for full `renderDeclaration` options.

## Server-side consent checks [#server-side-consent-checks]

To authorize backend work based on the same consent the runtime holds, request a short-lived token and verify it with `@optinstack/server`:

```js
const token = await window.OptinStack.getServerConsentToken();
// Send token to your API (default header: X-OptinStack-Consent)
```

See [JavaScript API → Server consent token](/api#server-consent-token).
