Custom widget runtime
Architecture
The SDK authenticates the user, loads the supplied custom bundle, and mounts the configured experience directly inside the host page.
Three values, three jobs
widget-idSelects the configured widget instance.
bundle-urlSelects the JavaScript bundle used by that experience.
embed-tokenCarries signed user identity for 15 minutes.
Load lifecycle
Page DOM
Custom bundles render inside the page. This gives the portal one scroll context and allows normal browser inspection.
Host page
└── <rai-custom-widget>
└── <div class="rai-widget-root">
└── Configured experience mounted by the supplied bundleScope host-page CSS
The widget is part of the page DOM. Broad selectors in the portal can affect its content, so scope application CSS to your own layout roots.
Authentication boundary
The access ID and access key stay in the client's backend. The browser receives only the short-lived embed token. The SDK sends that token to Returning.AI for validation before loading the configured experience.
- Server: stores access credentials and signs user identifiers into the token request.
- Browser: stores the current embed token in the element attribute and sends it to Returning.AI APIs.
- Returning.AI: validates the token and returns data for the authenticated user and configured widget.
Token lifecycle
Access Key embed tokens last 15 minutes and are not stored as refresh tokens in local storage. For long-lived pages, the host requests a fresh token from its backend and updates embed-token.
Register these observation listeners after your element exists. Use the complete shared host lifecycle for renewal, failure handling and account changes rather than adding an independent fetch handler.
const widget = document.querySelector('rai-custom-widget')
widget.addEventListener('rai-authenticated', () => {
console.log('Embed token accepted')
})
widget.addEventListener('rai-mounted', () => {
console.log('Custom bundle mounted')
})
widget.addEventListener('rai-session-expired', () => {
console.warn('Widget session needs attention')
})
// Observation only. Use the quickstart's shared host lifecycle
// for token renewal, bounded recovery and account-switch cleanup.Runtime API
The global window.ReturningAIWidget controller can report SDK version and auth state, reload the widget, return safe token metadata, or clear the session. DOM events remain scoped to each custom element.
In SDK 1.8.11, reload() tears down and initializes the widget again; it is not a lightweight progress query. Token synchronization updates authentication in a bundle or iframe, not proof of a fresh field, milestone or reward. Use rai-authenticated and rai-mounted as lifecycle signals, then check the configured visible business result separately.
Bundle releases, hosting and rollback
Pin the published SDK version separately from the supplied widget bundle. An npm version pins the SDK runtime, not the bundle URL's future contents. A URL shape alone does not establish an immutable release, supported version pair or rollback mechanism.
Before approving a bundle deployment, have the Returning.AI bundle owner and your release owner record the approved artifact/version or hash, supported SDK pair, change notice, tested rollback and permitted hosting model. Obtain the required script, connection and asset sources for your browser security policy; do not guess a version query parameter, mirror the bundle without approval or assume the SDK script is the only required source.
Keep these decisions in the existing handover. For an installed legacy loader, also follow the migration and rollback dependency checks.
Legacy runtime paths
The SDK still contains standard element tags, hosted iframe mode, auth-url, refresh-token storage, and a postMessage protocol for existing clients. New custom-widget integrations do not need those paths.
See the legacy embed documentation only when Returning.AI explicitly approves that method for your supplied setup. Retained runtime paths do not establish a support deadline or compatibility for an unknown loader.
Browser support
The SDK requires Custom Elements v1 and modern JavaScript. Current Chrome, Firefox, Safari, Edge, and Chromium-based in-app browsers are supported.