Banners
A separate, lightweight runtime for embedding Returning.AI banners on any page - no auth flow, no iframe. Available since SDK 1.6.0 as its own bundle, rai-banner.iife.js (~13 KB gzipped).
<rai-store-widget>, <rai-channel-widget>, ...) also renders eligible banners targeted at that widget type, and the widget element emits the same rai-banner-* events. Disable per widget with banner="off" (or the no-banner attribute). The standalone <rai-banner> element below is for pages with no widget.Embed
Custom element:
<script src="https://unpkg.com/@returningai/widget-sdk@1.8.6/dist/rai-banner.iife.js"></script>
<rai-banner community-id="YOUR_COMMUNITY_ID"></rai-banner>Or script-tag bootstrap (auto-creates the element):
<script
src="https://unpkg.com/@returningai/widget-sdk@1.8.6/dist/rai-banner.iife.js"
data-rai-banner
data-community-id="YOUR_COMMUNITY_ID"
></script>No mount <div> is required for any placement. Overlay and popup banners float over the page as a centered card; inline banners render into the banner's configured target selector, or in place where the element sits when that selector is not on the page.
Attributes
Attributes work with or without the data- prefix, on the element or the bootstrap script tag.
| Attribute | Required | Description |
|---|---|---|
| community-id | Yes | Your community ID from Community Settings. |
| api-url | No | Explicit API base URL (overrides domain-key). |
| domain-key | No | Environment key resolving the API host: LOCAL | SGTR | STG | GEN. Defaults to LOCAL, so production embeds should set the key Returning.AI gives them (or an explicit api-url). |
| surface | No | Eligibility surface. Defaults to sdk; leave it unless Returning.AI tells you otherwise. |
| page-path / page-hostname / page-url | No | Override the page context used for banner page rules. Defaults to window.location. |
| storage-prefix | No | localStorage key prefix for the anonymous visitor ID. |
| embed-token | No* | SDK embed token minted from your access ID/key, exactly like Access Key Embed for widgets. Required for banners whose Access setting is domain or SDK auth - see Access types below. |
<!-- Domain / SDK-auth banners: mint the embed token on your
server from your access id/key, exactly like widgets -->
<rai-banner
community-id="YOUR_COMMUNITY_ID"
embed-token="EMBED_TOKEN_FROM_YOUR_SERVER"
></rai-banner>How it works
- Mints or loads an anonymous visitor UUID in localStorage (
anonymous_session), enabling frequency caps and dismiss-memory without any PII. - Calls the public eligibility endpoint
POST /v2/api/banner-sdk/eligiblewith page and viewport context. - Renders the returned banner: overlay/popup placements as a centered card, inline into the configured target (or in place).
- Fires one-time, HMAC-signed impression / click / dismiss tracking URLs (replay-protected server-side).
- Banner HTML is sanitized client-side with DOMPurify before injection.
Access types
Each banner has an Access setting (chosen in the dashboard) that decides what the embed must provide:
| Banner Access | What the embed needs |
|---|---|
| Open to everyone | Nothing - community-id only. |
| Domain gate | The page is served from one of the banner's allowed domains (enforced on the request Origin), or an embed-token whose access key authorizes the origin. |
| SDK auth | A valid embed-token whose access key authorizes the origin. |
Widget-mounted banners pass the widget's embed-token automatically, so domain and SDK-auth banners work on widgets with no extra setup. A live banner whose surfaces include sdk is required.
Events
The element emits bubbling CustomEvents. Widget-mounted banners emit the same events from the widget element.
| Event | Detail |
|---|---|
| rai-banner-impression | { bannerId } |
| rai-banner-click | { bannerId } |
| rai-banner-dismiss | { bannerId } |
| rai-banner-empty | { reason } - no eligible banner |
| rai-banner-error | { error } |
document.addEventListener("rai-banner-impression", (e) =>
console.log("banner shown", e.detail.bannerId),
);
document.addEventListener("rai-banner-click", (e) =>
console.log("banner clicked", e.detail.bannerId),
);
document.addEventListener("rai-banner-dismiss", (e) =>
console.log("banner dismissed", e.detail.bannerId),
);
document.addEventListener("rai-banner-empty", (e) =>
console.log("no eligible banner", e.detail.reason),
);
document.addEventListener("rai-banner-error", (e) =>
console.error("banner error", e.detail.error),
);Note: since 1.6.0 the main widget bundle also makes one eligibility request per widget mount and bundles DOMPurify, so rai-widget.iife.js is slightly larger. Use banner="off" on a widget to skip that request.