If you’re using the embed widget npm package, you don’t need this page — the widget handles all postMessage communication internally. This protocol is for developers who embed the agent using a direct iframe and want programmatic control.
The Thesys agent iframe communicates with the parent window using the browser’s postMessage API. Messages are plain objects with a type field that identifies the action.
Parent → Iframe
Send messages to the agent by calling postMessage on the iframe’s contentWindow:
const iframe = document.getElementById('thesys-agent');
iframe.contentWindow.postMessage(
{ type: 'THESYS_SEND_MESSAGE', message: 'Hello!', newThread: false },
new URL(iframe.src).origin
);
// Reset the current thread (start a new chat)
iframe.contentWindow.postMessage(
{ type: 'THESYS_RESET_THREAD' },
new URL(iframe.src).origin
);
// Toggle the conversation history sidebar
iframe.contentWindow.postMessage(
{ type: 'THESYS_TOGGLE_SIDEBAR' },
new URL(iframe.src).origin
);
Always use a specific targetOrigin (e.g. new URL(iframe.src).origin) instead of "*" to prevent leaking data if the iframe navigates to an unexpected URL.
Message Types
| Type | Payload | Description |
|---|
THESYS_SEND_MESSAGE | { message: string, newThread: boolean } | Send a user message to the agent |
THESYS_SET_INPUT | { message: string, newThread: boolean } | Prefill the chat input without sending |
THESYS_IDENTITY_TOKEN_REFRESHED | { identityToken: string } | Provide a fresh identity token after a refresh request |
THESYS_RESET_THREAD | (none) | Start a new conversation thread, clearing the current chat |
THESYS_TOGGLE_SIDEBAR | (none) | Open or close the conversation history sidebar |
Iframe → Parent
The agent sends messages to the parent window. Listen for them with addEventListener:
const expectedOrigin = new URL(iframe.src).origin;
window.addEventListener('message', (event) => {
if (event.origin !== expectedOrigin) return;
if (!event.data || typeof event.data.type !== 'string') return;
switch (event.data.type) {
case 'THESYS_APP_READY':
// Agent has finished loading and is ready
break;
case 'THESYS_THREAD_CHANGED':
// Active thread changed — event.data.threadId
break;
case 'THESYS_NEW_THREAD':
// User started a new chat
break;
case 'THESYS_USER_MESSAGE_SENT':
// User sent a message — event.data.message, event.data.threadId
break;
case 'THESYS_GENERATION_STARTED':
// Agent started generating — event.data.threadId, event.data.messageId
break;
case 'THESYS_GENERATION_ENDED':
// Agent finished generating — event.data.threadId, event.data.messageId
break;
case 'THESYS_TOOL_EXECUTION_STARTED':
// Tool started — event.data.toolName, event.data.threadId
break;
case 'THESYS_TOOL_EXECUTION_ENDED':
// Tool finished — event.data.toolName, event.data.threadId, event.data.error
break;
case 'THESYS_AGENT_ERROR':
// Error occurred — event.data.code, event.data.message
break;
case 'THESYS_WIDGET_CLOSE':
// Agent requested to close
break;
case 'THESYS_WIDGET_OPEN':
// Agent requested to open
break;
case 'THESYS_WIDGET_TOGGLE':
// Agent requested to toggle open/close
break;
case 'THESYS_IDENTITY_TOKEN_REFRESH_NEEDED':
// Identity token expired — fetch a new one and send it back
break;
case 'THESYS_IDENTITY_TOKEN_ERROR':
// Identity token error — event.data.code, event.data.message
break;
}
});
Always validate event.origin against the expected iframe origin to prevent unauthorized windows from triggering actions.
Message Types
| Type | Payload | Description |
|---|
THESYS_APP_READY | (none) | The agent has finished loading and is ready for interaction |
THESYS_WIDGET_CLOSE | (none) | The agent is requesting to be closed |
THESYS_WIDGET_OPEN | (none) | The agent is requesting to be opened |
THESYS_WIDGET_TOGGLE | (none) | The agent is requesting to toggle its visibility |
THESYS_THREAD_CHANGED | { threadId: string } | The active conversation thread changed |
THESYS_NEW_THREAD | (none) | The user started a new chat (before the thread is created) |
THESYS_USER_MESSAGE_SENT | { message: string, threadId: string } | The user sent a message |
THESYS_GENERATION_STARTED | { threadId: string, messageId: string } | The agent started generating a response |
THESYS_GENERATION_ENDED | { threadId: string, messageId: string } | The agent finished generating a response |
THESYS_TOOL_EXECUTION_STARTED | { toolName: string, threadId: string } | A tool started executing |
THESYS_TOOL_EXECUTION_ENDED | { toolName: string, threadId: string, error?: string } | A tool finished executing |
THESYS_AGENT_ERROR | { code: string, message: string } | An error occurred during processing |
THESYS_IDENTITY_TOKEN_REFRESH_NEEDED | (none) | The identity token has expired; parent should provide a new one |
THESYS_IDENTITY_TOKEN_ERROR | { code: string, message: string } | An identity token error occurred |
If you’re using the embed widget npm package, you can use the higher-level Events API instead of listening for raw postMessage events.
Identity Token Refresh
When a BYOI identity token expires during an active session, the agent sends THESYS_IDENTITY_TOKEN_REFRESH_NEEDED to the parent. The parent should fetch a new token from its backend and reply with THESYS_IDENTITY_TOKEN_REFRESHED:
const iframe = document.getElementById('thesys-agent');
const agentOrigin = new URL(iframe.src).origin;
window.addEventListener('message', async (event) => {
if (event.origin !== agentOrigin) return;
if (event.data?.type === 'THESYS_IDENTITY_TOKEN_REFRESH_NEEDED') {
try {
const res = await fetch('/api/thesys-token');
const { token } = await res.json();
iframe.contentWindow.postMessage(
{ type: 'THESYS_IDENTITY_TOKEN_REFRESHED', identityToken: token },
agentOrigin
);
} catch (error) {
console.error('Failed to refresh identity token:', error);
}
}
});
If the parent doesn’t respond within 10 seconds, the agent shows an error modal to the user.
URL Parameters
When embedding via a direct iframe, you can configure the agent through URL query parameters:
| Parameter | Value | Description |
|---|
IDENTITY_TOKEN | JWT string | Sets the initial identity token for BYOI |
HIDE_LOGIN | "true" | Hides the Thesys login UI |
appRenderContext | TRAY_EMBED_WIDGET | FULLSCREEN_EMBED_WIDGET | CHATBAR_EMBED_WIDGET | Tells the agent which embed layout context it’s running in |
<iframe
id="thesys-agent"
src="https://console.thesys.dev/app/your-slug?IDENTITY_TOKEN=eyJ...&HIDE_LOGIN=true"
style="width: 100%; height: 600px; border: none;"
></iframe>