# SDK

The script that puts GoRunner in your page: `GoRunnerEmbed.mount()`, its options, methods, events and errors.

## 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.

```html
<script
  src="https://automations.example.com/embed.js"
></script>
```

Pinned to 1.4.0

```html
<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"`.

```js
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

- `container` · Required: The 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.
- `getCode` · Required: Returns 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](https://docs.gorunner.io/embed/sign-in-and-sessions).
- `url` · Optional: The installation’s address, such as `https://automations.example.com`, with no path. A path, query or credentials are refused with `invalid_options`. `/embed.js` fills it in with its own. The npm package needs it.
- `page` · Optional: Where it opens: `overview`, `workflows`, `runs`, `connections`, `templates`, `assistant`, `tokens`, or `{ workflow }`, `{ workflow, run }`, `{ run }`, `{ connection }`, `{ template }`, `{ path }`, or `{ newWorkflow: true }` with an optional `name`. Default: the first page the person may see.
- `theme` · Optional: `light`, `dark`, `system`: `system`, the default, follows your page’s color scheme. Ignored while Branding sets **Light or dark** to Light or Dark.
- `turnOff` · Optional: Switches to turn off for this page, at most 64. It can only turn things off. See [Switches](https://docs.gorunner.io/embed/switches).
- `appearance` · Optional: A look for this page, over the installation’s own. See [A look for one embed](https://docs.gorunner.io/embed/sdk#look).
- `onEvent` · Optional: Called with every event.
- `onBack` · Optional: Given, your page owns Back: the embed tells you instead of going back itself.
- `buildLink` · Optional: Given, **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.
- `title` · Optional: The frame’s accessible name, up to 200 characters. Default: the installation’s product name.
- `timeoutMs` · Optional: How 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, or `null` when none was.
- `setTheme(theme)`: Changes the theme, unless Branding fixes it.
- `setAppearance(look)`: Changes the look. `null` goes back to the installation’s. Resolves with `{ flags }`, what it corrected or couldn’t apply. Rejects with `invalid_appearance` for a look it refuses.
- `turnOff(keys)`: Turns more switches off.
- `switchAccount({ page? })`: Ends this session and asks `getCode` for a new code, with the reason `switch`: for the account your server now names. It loads a fresh document, so nothing of the old account stays, and opens `page`, else the mount’s named page, else the first allowed. Rejects with `busy` while 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-fatal `invalid_options` error event.
- `unmount()`: Ends the session and removes the frame, after waiting up to 3 seconds for it to save. Safe to call twice.

```js
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](https://docs.gorunner.io/embed/appearance) for this embed. Yours goes on top, leaf by leaf. Bars and menus stay solid.

- `preset`: `paper`, `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; `behind` is the color assumed under it.
- `corners`: `control`, `card`, `dialog`: 0 to 20.
- `depth`: `shadow`: `print`, `none`, `subtle`, `raised`. `frame`: `1` or `0`.
- `type`: `body`, `heading`, `baseSize` (13 to 16), `headingWeight` (500, 560, 600 or 700), `labelCase` (`upper` or `normal`). A font must be a WOFF2 or WOFF file on your page’s own website.
- `density`: `comfortable`, `compact`.
- `canvas.background`: `dots`, `grid`, `plain`.
- `fit`: `outerPadding` (0, 8, 12, 16, 24 or 32), `pageHeader`.
- `embedTheme`: `host` (**Follow the page**), `light` or `dark`.

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](https://docs.gorunner.io/embed/appearance#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`.

```js
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

```js
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](https://docs.gorunner.io/embed/events).

```js
const stop = embed.on("run.finished", (event) => {
  console.log(event.workflow, event.run.status)
})

embed.on("*", (event) => analytics.track(event.type))

stop() // stop listening
```

## Errors

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](https://docs.gorunner.io/embed/troubleshooting). For every code, see [Error codes › SDK](https://docs.gorunner.io/errors?kind=sdk).

```js
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)
}
```

Related: [Quick start](https://docs.gorunner.io/embed/quick-start) · [Events and the protocol](https://docs.gorunner.io/embed/events) · [Switches](https://docs.gorunner.io/embed/switches) · [Versions and upgrades](https://docs.gorunner.io/embed/versions)

Source: https://docs.gorunner.io/embed/sdk
