SDK
The script that puts GoRunner in your page: GoRunnerEmbed.mount(), its options, methods, events and errors.
This page needs your own installation with an Embed license.
Load it
Your installation serves the SDK. /embed.js is always the newest; it sets window.GoRunnerEmbed.
To pin a version, load it by number. SDK 1.3.0 is still served, byte for byte, for pages that check it with Subresource Integrity.
The SDK also has an npm package, @gorunner/embed, with a React component in @gorunner/embed/react. Neither is published yet. With the package, url is required.
The React component, not published yet
<GoRunnerEmbed url={…} getCode={getCode} accountKey={account.id} style={{ height: 640 }} />
It takes every mount() option except container, plus className, style, accountKey, embedRef, onReady(instance) and onError(error).
It mounts once. A changed theme calls setTheme, appearance (compared by value) setAppearance, new turnOff ids turnOff, and accountKey switchAccount. Removing a turnOff id needs a new key. url and page are read at mount only. Under StrictMode it still makes one frame, and on a server it renders an empty element.
<script
src="https://automations.example.com/embed.js"
></script>Pinned to 1.4.0
<script
src="https://automations.example.com/embed-sdk/1.4.0/embed.js"
></script>mount()
mount(options) opens the embed in your element and resolves when it is ready, with the embed itself. It rejects with an EmbedError when it can’t open.
getCode runs when the embed opens and whenever it needs a new session. Its reason is one of mount, renew, expired, reload, switch.
The embed’s state is mounting, ready, reconnecting, ended, unmounted. It also has id, route, account and unsaved. GoRunnerEmbed.protocol is the protocol it speaks, "gorunner-embed/1", and GoRunnerEmbed.version is the SDK’s version, such as "1.4.0".
const embed = await GoRunnerEmbed.mount({
container: "#automations",
getCode: async ({ reason }) => {
const url = "/api/gorunner/login-code"
const res = await fetch(url, { method: "POST" })
return (await res.json()).code
},
page: "workflows",
theme: "system",
turnOff: ["templates"],
onEvent: (event) => console.log(event.type),
})Options
containerRequiredThe element, or a selector for it. It needs a height: the embed fills it. Under 200 px tall, the frame gets a minimum of 640 px, and the console says so.
getCodeRequiredReturns a login code from your server, 1 to 512 characters. During a renewal the frame waits 15 seconds for it, and tries a few times before
session_failed. See Login codes and sessions.urlOptionalThe installation’s address, such as
https://automations.example.com, with no path. A path, query or credentials are refused withinvalid_options./embed.jsfills it in with its own. The npm package needs it.pageOptionalWhere it opens:
overview,workflows,runs,connections,templates,assistant,tokens, or{ workflow },{ workflow, run },{ run },{ connection },{ template },{ path }, or{ newWorkflow: true }with an optionalname. Default: the first page the person may see.themeOptionallight,dark,system:system, the default, follows your page’s color scheme. Ignored while Branding sets Light or dark to Light or Dark.turnOffOptionalSwitches to turn off for this page, at most 64. It can only turn things off. See Switches.
appearanceOptionalA look for this page, over the installation’s own. See A look for one embed.
onEventOptionalCalled with every event.
onBackOptionalGiven, your page owns Back: the embed tells you instead of going back itself.
buildLinkOptionalGiven, Copy link copies your page’s own address for a route. It must return an http or https address. Without it, there is no link to copy.
titleOptionalThe frame’s accessible name, up to 200 characters. Default: the installation’s product name.
timeoutMsOptionalHow long the embed may take to answer, in milliseconds: 5000 to 600000. Default 20000.
Methods
Each returns a promise. One that needs the frame rejects with not_ready until the embed is ready, and gives up after 10 seconds without an answer.
navigate(page)- Opens a page, with the same values as
page. Resolves with the route reached. connect({ piece })- Opens the connection sheet for one app. Resolves with
{ connection }: the connection made, ornullwhen none was. setTheme(theme)- Changes the theme, unless Branding fixes it.
setAppearance(look)- Changes the look.
nullgoes back to the installation’s. Resolves with{ flags }, what it corrected or couldn’t apply. Rejects withinvalid_appearancefor a look it refuses. turnOff(keys)- Turns more switches off.
switchAccount({ page? })- Ends this session and asks
getCodefor a new code, with the reasonswitch: for the account your server now names. It loads a fresh document, so nothing of the old account stays, and openspage, else the mount’s named page, else the first allowed. Rejects withbusywhile signing in. on(type, listener)- Listens to one event, or
"*"for all. Returns a function that stops it. A type no event has is accepted, with a console warning and a non-fatalinvalid_optionserror event. unmount()- Ends the session and removes the frame, after waiting up to 3 seconds for it to save. Safe to call twice.
const workflowId = "your-workflow-id" // from workflow.created
await embed.navigate({ workflow: workflowId })
await embed.navigate({
newWorkflow: true,
name: "Order intake",
})
const { connection } = await embed.connect({
piece: "gmail",
})
await embed.setTheme("dark")
await embed.turnOff(["delete", "importExport"])
await embed.switchAccount({ page: "overview" })
await embed.unmount()A look for one embed
The appearance option at mount, or setAppearance() later, lays a look over the installation’s Branding for this embed. Yours goes on top, leaf by leaf. Bars and menus stay solid.
presetpaper,soft,crisp.colors- Ten roles,
brand,onBrand,page,surface,raised,border,text,textMuted,link,focus, each{ light, dark }as#rrggbb.page: "transparent"lets your page show through, in the embed only;behindis the color assumed under it. cornerscontrol,card,dialog: 0 to 20.depthshadow:print,none,subtle,raised.frame:1or0.typebody,heading,baseSize(13 to 16),headingWeight(500, 560, 600 or 700),labelCase(upperornormal). A font must be a WOFF2 or WOFF file on your page’s own website.densitycomfortable,compact.canvas.backgrounddots,grid,plain.fitouterPadding(0, 8, 12, 16, 24 or 32),pageHeader.embedThemehost(Follow the page),lightordark.
A look is at most 16 KB as JSON. A font service’s stylesheet is refused (invalid_appearance, font_stylesheet): a font is one font file. Up to 8 KB rides in the frame’s address fragment, which never reaches a server, so even the first paint wears it. What the frame changed comes back as flags.
GoRunnerEmbed.matchHost() proposes a look from your page’s own styles: its background, text, font, a button and a card. It never applies anything. Its options are root, button, card and allowedOrigins. It answers appearance, the theme it read, the flags the frame will raise, and notes on what it couldn’t read: no_background, gradient_background, font_not_loadable, font_cross_origin, button_not_found, button_transparent, card_not_found, radius_clamped, shadow_unrecognised.
const embed = await GoRunnerEmbed.mount({
container: "#automations",
getCode,
appearance: {
preset: "soft",
colors: { brand: { light: "#0f6e5a", dark: "#5cc8a8" } },
corners: { control: 8, card: 12 },
density: "compact",
fit: { outerPadding: 0, pageHeader: false },
},
})
const { flags } = await embed.setAppearance({
colors: {
page: { light: "transparent", behind: { light: "#f7f7f5" } },
},
})A look proposed from your page
const proposal = GoRunnerEmbed.matchHost({ root: "#automations" })
const embed = await GoRunnerEmbed.mount({
container: "#automations",
getCode,
appearance: proposal.appearance,
})Events
- The embed
ready,error,session.renewed- Where it is
route.changed,title.changed,back,unsaved.changed- Workflows
workflow.created,workflow.saved,workflow.published,workflow.unpublished,workflow.deleted- Runs
run.started,run.finished,run.failed- Connections
connection.created,connection.removed
Each event’s fields are in Events and the protocol.
const stop = embed.on("run.finished", (event) => {
console.log(event.workflow, event.run.status)
})
embed.on("*", (event) => analytics.track(event.type))
stop() // stop listeningErrors
Everything that fails rejects with an EmbedError, with code, message and sometimes details. After mounting, problems arrive as the error event, such as account_suspended.
For what to do about each, see Troubleshooting. For every code, see Error codes › SDK.
try {
await GoRunnerEmbed.mount({ container, getCode })
} catch (error) {
// an EmbedError
if (error.code === "not_allowed_here") {
// add this website under Platform › Partner keys
}
console.error(error.code, error.message)
}