Skip to Content
GuidesConsent banner

Consent banner

The <asiri-consent> component is part of the @asiri-ng/elements family — a collection of dependency-free web components for Asiri. It renders a cookie-consent banner, captures the visitor’s choices, and writes a signed record to your Asiri consent ledger — all without any backend code on your side.

Prerequisites

  • You must have a published consent notice in your workspace. Go to Compliance → Consent notices, publish the notice, then open Developer → Embeds to find its notice ID. Alternatively, call GET /v1/public/consent/{noticeId} — if the notice exists and is published, it returns the notice details; a 404 means it hasn’t been published yet.
  • The notice’s domain must match the site you embed on. The API returns 403 consent_origin_not_allowed for records submitted from any other origin.

Quick start — no build required

Paste two lines before your closing </body> tag:

<script async src="https://cdn.jsdelivr.net/npm/@asiri-ng/elements@0.1.0/dist/consent.global.js" integrity="sha384-REPLACE_WITH_SRI_HASH" crossorigin="anonymous" ></script> <asiri-consent notice-id="YOUR_NOTICE_ID"></asiri-consent>

Replace YOUR_NOTICE_ID with the ID from Developer → Embeds. Replace REPLACE_WITH_SRI_HASH with the Subresource Integrity hash published in the release notes  for the version you pin — each release publishes the sha384- digest for its CDN bundle. Loading an external script without SRI exposes your site to CDN-level compromise, so always pin both the version and its hash.

The banner appears on first visit and disappears once the visitor makes a choice. Returning visitors who have already decided see no banner.

Attributes

AttributeRequiredDefaultDescription
notice-idYesYour published consent notice ID.
api-baseNohttps://api.asiri.ngOverride the API base URL (e.g. staging).

Install via npm

For React, Vue, Svelte, or any bundler-based project:

pnpm add @asiri-ng/elements

Import the consent component once — it self-registers the asiri-consent custom element and sets up window.AsiriConsent:

import '@asiri-ng/elements/consent';

Then place the element anywhere in your markup:

<asiri-consent notice-id="YOUR_NOTICE_ID"></asiri-consent>

React

The element is a standard custom element and works directly in JSX. TypeScript users: cast it with as any or add a global JSX namespace extension until @asiri-ng/elements ships React types.

import '@asiri-ng/elements/consent'; export function App() { const noticeId = process.env.NEXT_PUBLIC_ASIRI_NOTICE_ID!; return ( <> {/* your app */} <asiri-consent notice-id={noticeId} /> </> ); }

WordPress / Google Tag Manager

Paste the script-tag version into a Custom HTML block (WordPress block editor) or a Custom HTML tag (GTM):

<script async src="https://cdn.jsdelivr.net/npm/@asiri-ng/elements@0.1.0/dist/consent.global.js" integrity="sha384-REPLACE_WITH_SRI_HASH" crossorigin="anonymous" ></script> <asiri-consent notice-id="YOUR_NOTICE_ID"></asiri-consent>

Use the SRI hash from the release notes .


Use window.AsiriConsent to load third-party scripts only after the visitor decides.

window.AsiriConsent.onDecision((state) => { if (state.purposes.analytics) { // initialise your analytics library here } if (state.purposes.marketing) { // load ad pixels here } });

onDecision fires immediately if a stored decision already exists (e.g. returning visitor), so your scripts load without waiting for banner interaction. The callback receives a ConsentState object:

interface ConsentState { decided: boolean; // always true inside the callback purposes: Record<string, boolean>; // purpose key → granted }

Purpose keys match the keys you defined on the notice (for example strictly_necessary, analytics, marketing). Required purposes are always true.

Re-open the preferences panel

Add a “Cookie settings” link in your footer and call window.AsiriConsent.open():

document.querySelector('#cookie-settings').addEventListener('click', () => { window.AsiriConsent.open(); });

Read the current state synchronously

const state = window.AsiriConsent.get(); // state is null until the visitor has decided, or ConsentState after.

DOM event

The element also dispatches a asiri-consent event on document whenever a decision is recorded or loaded from storage. Listen for it if you prefer events over callbacks:

document.addEventListener('asiri-consent', (event) => { const { decided, purposes } = event.detail; // same shape as ConsentState });

Full window.AsiriConsent API

MethodReturnsDescription
get()ConsentState | nullCurrent decision, or null before any decision.
onDecision(cb)() => voidSubscribe to decisions; fires immediately if already decided. Returns an unsubscribe function.
open()voidRe-open the preferences panel.

Record or read consent from your backend using an API key and the official SDKs. This is useful when you collect consent outside the browser — for example during a phone call, in a mobile app, or through a paper form.

Requires a secret API key with consent:write / consent:read scope. See Getting Started → API Keys.

TypeScript / Node

Install the SDK: SDKs → TypeScript.

import { createAsiriClient } from '@asiri-ng/sdk-ts'; const client = createAsiriClient({ baseUrl: 'https://api.asiri.ng', apiKey: process.env.ASIRI_API_KEY, }); // Record a consent decision const record = await client.consent.record('NOTICE_ID', { subjectId: 'user_123', purposes: { strictly_necessary: true, analytics: true, marketing: false }, method: 'phone', }); // List records for a notice (paginated) const page = await client.consent.listRecords('NOTICE_ID', { limit: 50 }); // Fetch a single record const single = await client.consent.getRecord('NOTICE_ID', record.id);

Python

Install the SDK: SDKs → Python.

from asiri import AsiriClient client = AsiriClient( base_url="https://api.asiri.ng", api_key=os.environ["ASIRI_API_KEY"], ) # Record a consent decision record = client.consent.record( "NOTICE_ID", "user_123", purposes={"strictly_necessary": True, "analytics": True, "marketing": False}, method="phone", ) # List records for a notice (paginated) page = client.consent.list_records("NOTICE_ID", limit=50) # Fetch a single record single = client.consent.get_record("NOTICE_ID", record["id"])

Public REST API reference

The two endpoints below are unauthenticated and CORS-open — any origin can call them from a browser. They are not included in the auto-generated API reference because they use a separate public authentication model.

Get a published notice

Fetch the notice definition, including its purposes. Returns 404 if the notice doesn’t exist or hasn’t been published.

GET https://api.asiri.ng/v1/public/consent/{noticeId}

Response — 200

{ "data": { "id": "ntc_01jv3q4e5f0000000000000000", "name": "Main website", "controllerName": "Acme Ltd", "language": "en", "domain": "acme.com", "purposes": [ { "key": "strictly_necessary", "label": "Strictly necessary", "description": "Required for the site to function. Cannot be disabled.", "required": true }, { "key": "analytics", "label": "Analytics", "description": "Helps us understand how visitors use the site.", "required": false }, { "key": "marketing", "label": "Marketing", "description": "Used to deliver relevant advertising.", "required": false } ] } }

Error — 404 — notice not found or not published.


Record a visitor’s consent decision. The web component calls this endpoint automatically; call it directly only if you’re building a custom consent UI.

POST https://api.asiri.ng/v1/public/consent/{noticeId}/records

Request body

{ "subjectId": "anon-a1b2c3d4", "purposes": { "strictly_necessary": true, "analytics": true, "marketing": false }, "method": "banner", "capturedAt": "2026-06-23T09:15:00.000Z" }
FieldTypeRequiredDescription
subjectIdstringYesPseudonymous identifier for the visitor (e.g. a UUID from local storage).
purposes{ [key: string]: boolean }YesOne entry per purpose key from the notice.
methodstringNoHow consent was captured — e.g. "banner", "phone".
capturedAtISO 8601 stringNoWhen consent was captured. Defaults to server time.

Response — 201 — record created.

Error — 403 consent_origin_not_allowed — the request Origin does not match the notice’s configured domain. Verify that the notice domain matches the site you’re embedding on.

Privacy notes

  • The request Origin is validated against the notice domain but not stored.
  • Raw IP addresses and user-agent strings are never persisted — only salted hashes.
  • The endpoint is rate-limited per notice to prevent abuse.