Events and the protocol
What the embed tells your page, when, and with what, and the messages underneath.
This page needs your own installation with an Embed license.
Listen with onEvent at mount, or embed.on(type, listener) for one type, "*" for all. Every event is a flat object with a type. Ids are the installation’s, except account.id and user.id, which are yours. An event carries only what your server could already read through the Partner API: never a token or a run’s data.
const embed = await GoRunnerEmbed.mount({
container: "#automations",
getCode,
onEvent: (event) => console.log(event.type, event),
})
embed.on("run.failed", ({ run, workflow, message }) => {
notify(`${workflow.name} failed: ${message ?? ""}`)
})Events tell your page what happens in the open embed. Your server hears about accounts whether or not anyone has them open, through notifications.
Every event
| Event | Fields | When |
|---|---|---|
| The embed3 | ||
account: { id, name }, user: { id, name }, role, path, page | Signed in and showing its first page: when | |
code, message, fatal | Something went wrong after mounting. See The error event. | |
expiresAt | The session was renewed without the person noticing, by itself or with a new code. It ends 30 minutes after it began. | |
| Where it is4 | ||
path, page, title, replace | The person moved inside the embed. A path the protocol can’t name isn’t told. | |
title, parent? | The page’s name changed, such as a workflow once it loads, with the list it belongs to. | |
path, page | The person pressed the embed’s back arrow. With | |
unsaved, workflow: { id } or null | The open workflow gained or lost unsaved changes. Use it to warn before your page navigates away. | |
| Workflows5 | ||
workflow: { id, name } | Made new, duplicated, imported, or from a template. | |
workflow: { id, name } | Changes saved. | |
workflow: { id, name } | Published, including a template made with Create and publish. | |
workflow: { id, name } | Switched off. | |
workflow: { id } | Deleted. | |
| Runs3 | ||
run: { id }, workflow, kind | A run was started from the embed. | |
run: { id, status, durationMs? }, workflow | A run started from the embed ended: | |
run: { id, durationMs? }, workflow, step?, message? | A run started from the embed failed, at | |
| Connections2 | ||
connection: { id, name, piece } | A new connection is ready, from anywhere in the embed or your page’s | |
connection: { id } | A connection was deleted. | |
Workflow and run events come from one place in the frame, whoever pressed the button: the person, the assistant or a template. So each happens once.
The frame watches a run it started for up to 30 minutes: every 2 seconds for the first 2, then every 10. A run waiting for an approval or a delay is still running. A run that ends later isn’t told here.
The error event
fatal: true means the embed can go no further: its state becomes ended, and it shows the person why. fatal: false is worth knowing while the embed carries on. Branch on code; message is for a developer.
code | Fatal | What happened |
|---|---|---|
account_suspended | No | Everything can be read; nothing can change or run. |
not_available | No | A page the person reached isn’t available to them here: switched off, or its record couldn’t be loaded. |
session_failed | No | A renewal failed: your page didn’t hand over a new code in time. The frame offers to try again. |
code_expired | Either | The code was used or too old, twice. During a renewal the frame carries on; on a reload it is fatal. |
access_ended | Yes | The person no longer has access to this account. |
licence | Yes | The license no longer includes Embed, or the installation is paused. |
unavailable | Yes | The installation runs with sign-in turned off, or no page is switched on for this person any more. |
code_failed | Yes | Signing in again, after a reload or an account switch, your getCode failed. |
unreachable | Yes | Signing in again, the frame couldn’t reach the installation. |
version_mismatch | Yes | After an upgrade, the frame and the SDK share no protocol version. |
timeout | Yes | Signing in again, the frame didn’t answer in time. |
crashed | Yes | The frame hit an error it couldn’t recover from. It offers the person a reload. |
not_allowed_here, container_not_found, invalid_options and unmounted reach you as a mount() rejection, not as this event. So does not_available when the page you named at mount is switched off.
The protocol
Your page and the frame talk only through postMessage, in gorunner-embed/1. The SDK speaks it for you.
- One envelope
{ protocol: "gorunner-embed/1", id, type, payload }, both ways.- Exact origin, exact window
- Each side reads a message only from the exact origin and window it expects, and never posts to
"*". The frame answers only a page on the allowed websites. - Checked and bounded
- Every message is checked against its shape before it is read. One over 262,144 characters as JSON is refused unread.
- Nothing widens access
- Your page can turn things off and move between pages it may show. No message turns anything on.
- The messages
- The frame sends
ready,authenticated,configured,failed,event,request,reply. Your page sendsinit,command,reply; the commands arenavigate,connect,setTheme,setAppearance,turnOff,teardown. - What version 1 promises
- The envelope, the message types, the handshake order, how a reply is matched, and the meaning of every code never change. Anything else may only be added, and both sides ignore what they don’t know.