Legacy approach. For new integrations, use the Widget SDK with Access Key Embed.
Server-Side Proxy
The most secure integration method. Your server fetches the widget HTML from Returning.AI, injects the JWT token server-side, and serves it to the browser. The API key never touches the client.
Integration method, not authentication method
Server-Side Proxy is one of three ways to integrate Returning.AI widgets (alongside the Widget SDK and Embed Script). It uses Token Authentication under the hood. If you haven't read about Token Auth yet, start there first.
Architecture
Every request flows through your backend. The browser never communicates directly with the Returning.AI API.
Browser -> Your Server -> Returning.AI API
|
1. POST /widget/{id}/signin (get JWT)
2. GET /{widget-type}/{widgetId} (get HTML)
3. Inject token into HTML
|
Browser <- Modified HTML with embedded tokenSecurity model
A clear separation between server-side secrets and browser-visible data.
| Stays on your server | Goes to the browser |
|---|---|
WIDGET_API_KEY | JWT (short-lived, user-scoped) |
WIDGET_COMMUNITY_ID | Widget ID |
| Returning.AI API requests | Rendered widget HTML (with token embedded) |
When to use
- Maximum security requirements - API key never leaves the server.
- Full control over the widget lifecycle (caching, error pages, fallbacks).
- Domain whitelisting is insufficient for your security model.
Getting started
Five steps from zero to a working server-side proxy.
1Store credentials server-side
Keep your API key and community ID in environment variables. They must never be included in client-side code or HTML responses.
WIDGET_BASE_URL=https://prod-widgets.returning.ai
WIDGET_API_KEY=your-api-key
WIDGET_COMMUNITY_ID=your-community-id
WIDGET_ID=your-widget-id
WIDGET_TYPE=store2Accept user email from an authenticated request
The email must come from your verified session or auth middleware - never from a query parameter or request body that the client controls directly.
3Fetch a JWT from Returning.AI
POST the user's email along with your API key to the signin endpoint.
POST /widget/{communityId}/signin
Headers:
Content-Type: application/json
returningai-api-key: YOUR_API_KEY
email: user@example.com
Response:
{ "token": "eyJhbGciOiJIUzI1NiIs..." }4Fetch widget HTML
GET the widget page. The HTML comes with an empty token placeholder in the __WIDGET_INIT__ config.
GET /{widget-type}/{widgetId}?color=light
Response:
<!DOCTYPE html>
<html>
<head>...</head>
<body>
<script>
window.__WIDGET_INIT__ = { token: "", ... };
</script>
...
</body>
</html>5Inject token into HTML and serve
Replace the empty token placeholder with the JWT, then send the modified HTML to the browser.
// Replace the empty token placeholder with the real JWT
html = html.replace(/token:\s*""/, `token: "${safeToken}"`);How this differs from Widget SDK and Embed Script
Unlike the Widget SDK or Embed Script methods, the server-side proxy gives you complete control over the authentication flow but requires more backend work. The tradeoff is maximum security for additional implementation effort.