Embed API
Securely embed Streamr in partner applications with authenticated users.
Use this reference when integrating Streamr into a partner application. For setup and a live preview, use Configure an Embed. For API-key creation (admins only), token generation and token validation, use Embed API Utilities.
HTTPS Required
Embed authentication uses cookies with sameSite=none to work in third-party iframe contexts. This requires HTTPS in production.
- Both your app and the parent page must use HTTPS.
- Session cookies will not work over HTTP in production.
- For local testing, use tools like ngrok or configure local HTTPS.
Configure an Embed
Configure authentication, choose Creator, Agent, or Showcase mode, and preview your embed in a live iframe.
Overview
The Streamr Embed API authenticates users inside embedded iframes using JWT tokens. This provides a single sign-on style experience without forcing users through an OAuth flow inside the iframe.
There are two authentication paths:
- API Key to Embed JWT: call
/api/embed/generateTokenwith your API key and a user email to get a short-lived signed JWT, then pass it as?token=. - Auth0 Access Token: if you already have an Auth0 access token for the user, pass it directly as
?token=. The embed validates it through Auth0/userinfoand resolves the email automatically.
Embed Modes
The embed supports Creator, Agent and Showcase modes through the mode query parameter.
Creator Mode
Creator mode is the default. It opens the creative editor for generating and editing ad creatives.
/embed?token=TOKEN
Agent Mode
Agent mode opens the AI Chat agent with navigation between Chat, Creatives, and Campaigns. Create, edit, and save flows work normally within the iframe.
/embed?token=TOKEN&mode=agent
In agent mode, users can navigate between AI Chat, Creatives, and Campaigns using the tab bar. Save actions redirect within the iframe, and users can tab back to chat.
Showcase Mode
Showcase mode opens the delegated publisher workspace. It requires an Auth0 access token and authorized SpringServe publisher context; the URL does not grant account access.
/embed?token=AUTH0_ACCESS_TOKEN&mode=showcase&authContext=springserve/publisher/ACCOUNT_ID
Use Configure an Embed to choose an accessible publisher account. Existing downstream account and role checks still apply.
Appearance and Agent Options
| Parameter | Applies to | Behavior |
|---|---|---|
theme=light or theme=dark | All modes | Locks the iframe theme without changing the user's saved preference. Omit to inherit the saved or system theme. |
header=false | Agent | Hides the agent header. |
agent | Agent | Locks the selected agent; use the configurator's available built-in or activated custom agents. |
authContext | Agent or Showcase | Selected account context in platform/type/id format; existing access checks apply. Showcase requires springserve/publisher/<id>. |
user | Agent | URL-encoded opening prompt. It is submitted once when the chat is ready; on brands requiring an account choice, the user selects the account and submits it manually. |
/embed?token=TOKEN&mode=agent&theme=dark&user=Help%20me%20review%20a%20campaign
Integration Practices
Generate API-key tokens on your backend and keep API keys out of client code. Use the appropriate Auth0 tenant for staging or production. Choose short expiration times for sensitive operations and handle auth-expired messages to refresh the iframe. Include allow="geolocation" only when the integration needs high-accuracy place autocomplete; IP-based location remains the fallback.
API Reference
Generate Token
POST /api/embed/generateToken
Generate a signed JWT token for embed authentication.
Headers:
X-API-Key: your-api-key
Request body:
{
"email": "user@example.com",
"expiresIn": "24h"
}
Response:
{
"success": true,
"token": "eyJhbGc...",
"embedUrl": "https://yourapp.com/embed?token=eyJhbGc...",
"expiresIn": "24h"
}
Validate Token
POST /api/embed/validateToken
Validate a token and create a user session. This accepts both Streamr embed JWTs and Auth0 access tokens.
Request body:
{
"token": "eyJhbGc..."
}
Response for a Streamr embed JWT:
{
"success": true,
"tokenValid": true,
"user": {
"email": "user@example.com",
"organizationId": "org-123",
"organizationName": "Acme Corp"
}
}
Response for an Auth0 access token in cookie-free or Safari mode:
{
"success": true,
"tokenValid": true,
"user": { "email": "user@example.com" },
"sessionToken": "eyJhbGc..."
}
When third-party cookies are blocked, the embed uses cookie-free mode. For Auth0 tokens, /api/embed/validateToken issues a short-lived Streamr embed JWT in sessionToken so the middleware receives a locally verifiable token on later requests.
Embedding in Your App
For a Streamr embed JWT generated through the API key path:
<iframe
src="https://your-instance.com/embed?token=YOUR_EMBED_JWT_HERE"
width="100%"
height="600"
frameborder="0"
allow="clipboard-write; geolocation"
></iframe>
For a direct Auth0 access token:
<iframe
src="https://your-instance.com/embed?token=YOUR_AUTH0_ACCESS_TOKEN_HERE"
width="100%"
height="600"
frameborder="0"
allow="clipboard-write; geolocation"
></iframe>
The email is resolved from the Auth0 token automatically. Staging tokens validate against the staging Auth0 tenant; production tokens validate against production.
Loading a Saved Creative
To open the embed with a previously saved creative pre-loaded, add creativeId and createdAt query parameters.
<iframe
src="https://your-instance.com/embed?token=YOUR_TOKEN_HERE&creativeId=cr_xxx&createdAt=2026-01-06T17%3A18%3A51.926Z"
width="100%"
height="600"
frameborder="0"
allow="clipboard-write; geolocation"
></iframe>
Parameters:
| Parameter | Required | Description |
|---|---|---|
token | Yes | Streamr embed JWT or Auth0 access token. |
creativeId | No | Creative ID, such as cr_1767719931926_2tfqjs9. |
createdAt | No | URL-encoded ISO 8601 creation timestamp. |
When both creativeId and createdAt are provided, the embed fetches the creative after authentication and loads its template, settings, and media into the player. Editing and saving creates a new creative; the original is not modified.
PostMessage Events
Creative Saved
When a user saves a creative in the embed, the parent window receives a message with the saved creative data.
window.addEventListener('message', (event) => {
const message = event.data
if (message.type === 'creative-saved') {
const creativeId = message.creative.data.entityId.split('#')[2]
const createdAt = message.creative.data.createdAt
console.log('Creative ID:', creativeId)
console.log('Created At:', createdAt)
}
})
Message shape:
{
"type": "creative-saved",
"creative": {
"success": true,
"data": {
"entityOwner": "PLAT#streamr#USER#user@example.com",
"entityId": "CREATIVE#2026-01-06T17:18:51.926Z#cr_1767719931926_2tfqjs9",
"createdAt": "2026-01-06T17:18:51.926Z",
"updatedAt": "2026-01-06T17:18:51.926Z"
}
}
}
Re-Opening a Saved Creative
After capturing a creative-saved event, re-open that creative by including its ID and timestamp in the iframe URL.
window.addEventListener('message', (event) => {
const message = event.data
if (message.type === 'creative-saved') {
const creativeId = message.creative.data.entityId.split('#')[2]
const createdAt = message.creative.data.createdAt
const token = 'YOUR_TOKEN_HERE'
iframe.src = `https://your-instance.com/embed?token=${token}`
+ `&creativeId=${creativeId}`
+ `&createdAt=${encodeURIComponent(createdAt)}`
}
})
Auth Expired
When a user's session or token expires inside creator or agent mode, the iframe posts an auth-expired message so the parent page can generate a fresh token and reload the iframe.
window.addEventListener('message', async (event) => {
const message = event.data
if (message.type === 'auth-expired') {
const newToken = await fetchNewTokenFromYourBackend()
iframe.src = `${location.origin}/embed?token=${newToken}`
}
})
Message shape:
{
"type": "auth-expired"
}
Embed Resize
Creator mode continuously monitors its content height and posts an embed-resize message when it changes. Use this to resize the iframe so it fits its content. This event is not emitted in agent mode; use a fixed height such as 800px.
window.addEventListener('message', (event) => {
if (event.data.type === 'embed-resize' && typeof event.data.height === 'number') {
iframe.style.height = event.data.height + 'px'
}
})
Message shape:
{
"type": "embed-resize",
"height": 742
}
Always verify event.origin in production before processing messages.
API Calls After Embed Auth
After token validation, use the session cookie for API requests.
Get all templates:
const response = await fetch(`${baseUrl}/api/templates`, {
headers: { Cookie: sessionCookie }
})
const { templates, defaultTemplateId } = await response.json()
Get a specific creative:
const response = await fetch(
`${baseUrl}/api/creatives/${creativeId}?userEmail=${encodeURIComponent(userEmail)}&createdAt=${encodeURIComponent(createdAt)}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
Cookie: sessionCookie
}
}
)
const creative = await response.json()
Start a video render:
const response = await fetch(`${baseUrl}/api/creatomate/render`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Cookie: sessionCookie
},
body: JSON.stringify({
templateId: '82881724-b4df-48d6-ae49-51c7ee44640f',
modifications: {
'Text-1': 'Hello World',
'Image-1': 'https://example.com/image.jpg'
},
pollUntilComplete: false
})
})
const result = await response.json()
Check render status:
const response = await fetch(`${baseUrl}/api/creatomate/check-render?renderId=${renderId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Cookie: sessionCookie
}
})
const statusResult = await response.json()
Testing and MCP Integration
- MCP Test Console (admin access required) to test initialization, tool discovery, tool calls, responses, and errors with your browser session.
- Open AI Agent to test the chat interface that uses MCP under the hood.
- For external agents, call
POST /api/mcpand include the embed token in thex-api-keyheader.
Embed API Utilities
Embed API Utilities provides interactive token generation and validation, copyable request examples, and admin API-key creation. It also shows brand-specific broadcast download details when configured. These actions retain their existing login and API access requirements.

