GoRunner docs
Search or askSearch⌘K

Quick start

Show GoRunner inside your app, signed in as your customer.

15 min · Embed · Self-hosted with an Embed license

You need

An installation with an Embed license
Licenses come from GoRunner: see Your license. No installation yet: Install with Docker. Without Embed, the partner API answers 403 EMBED_NOT_LICENSED.
An instance-wide platform admin
With two-factor on. Each change on Partner keys asks for your two-factor code.
A server
The one behind your app, where your customers are signed in: Node.js 18, Python 3.7, Go 1.22 or PHP 8.4, or newer. Any language works: it makes one HTTP call.

For the admin half, with every option, see Set up Embed.

1.Make a partner key

  1. In GoRunner, open Platform › Partner keys and press Make a key….
  2. Name it, such as Production backend, press Make the key, and enter your two-factor code.
  3. Press Copy the key and keep it on your server. You won’t see it again.
Platform › Partner keys, with the Make a key… button ringed.

You should see the key in the list, shown by its start: gre_5e0b91c2….

2.Allow your website

  1. On the same page, under Allowed websites, enter your app’s address, such as https://app.acme.example. Use the address only, with no path.
  2. Press Add and enter your two-factor code.

The embed opens only on pages of allowed websites.

What if I try it on my own machine?

Plain http works for localhost, 127.0.0.1 and [::1]. Add the address exactly as your browser shows it, such as http://localhost:3000: http://127.0.0.1:3000 is another website.

3.Hand out login codes from your server

Your page never sees the partner key. It asks your server for a login code, and your server asks GoRunner for one, for the person signed in to your app.

// POST /api/gorunner/login-code → {"code": "grl_…"}
import { createServer } from "node:http"

const GORUNNER_URL = process.env.GORUNNER_URL // the installation
const GORUNNER_EMBED_KEY = process.env.GORUNNER_EMBED_KEY // gre_…
const PORT = Number(process.env.PORT || 3000)

// Who is signed in to your app: replace this with your own session
// lookup. Answer null when nobody is signed in.
function signedIn(req) {
  return {
    user: {
      id: "ada-123",
      name: "Ada Lovelace",
      email: "ada.lovelace@example.com",
    },
    account: { id: "acct-bakery", name: "Bakery Ltd" },
    role: "editor", // viewer, operator or editor
  }
}

function send(res, status, body) {
  res.writeHead(status, {
    "Content-Type": "application/json",
    "Cache-Control": "no-store",
  })
  res.end(JSON.stringify(body))
}

createServer(async (req, res) => {
  if (req.method !== "POST" || req.url !== "/api/gorunner/login-code")
    return send(res, 404, { error: "not found" })
  const login = signedIn(req)
  if (!login) return send(res, 401, { error: "sign in first" })
  try {
    const url = `${GORUNNER_URL}/api/embed/v1/login-codes`
    const answer = await fetch(url, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${GORUNNER_EMBED_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(login),
    })
    const body = await answer.json()
    if (answer.status !== 201) {
      console.error("refused:", answer.status, body.error?.code)
      return send(res, 502, { error: "login code refused" })
    }
    send(res, 200, { code: body.data.code })
  } catch (e) {
    console.error("login code failed:", e.message)
    send(res, 502, { error: "login code failed" })
  }
}).listen(PORT)

Replace signedIn() with your own session lookup. Send each person’s real role: editor builds and publishes, operator runs, viewer looks. A later code with another role changes it. Make a code only for an account the person belongs to.

Then start it with your installation’s address and your key (gre_…). Until signedIn() reads your real session, it hands an editor’s code to anyone who reaches it: run it where only you can.

GORUNNER_URL=https://automations.example.com \
GORUNNER_EMBED_KEY=YOUR_PARTNER_KEY \
node server.mjs

You should see curl -X POST localhost:3000/api/gorunner/login-code answers {"code":"grl_…"}. A code works once, within 60 seconds.

4.Add the embed to your page

The script comes from your installation. getCode runs when the embed opens, and again whenever it needs a new session.

automations.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Automations</title>
  </head>
  <body>
    <main>
      <h1>Automations</h1>
      <!-- The embed fills this element, so give it a height. -->
      <div id="automations" style="height: 720px"></div>
    </main>
    <script src="https://automations.example.com/embed.js"></script>
    <script>
      GoRunnerEmbed.mount({
        container: "#automations",
        // Called at mount, and whenever the embed needs a new session.
        getCode: async () => {
          const answer = await fetch("/api/gorunner/login-code", {
            method: "POST",
          })
          if (!answer.ok) throw new Error(`login code: ${answer.status}`)
          return (await answer.json()).code
        },
      }).catch((error) => {
        console.error("The automations could not open:", error.code)
      })
    </script>
  </body>
</html>

The element needs a height: the embed fills it.

Serve the page from the same website as your login-code route: getCode asks /api/gorunner/login-code on the page’s own address. The example servers answer only that route, so add one that answers GET / with this page.

5.Open your page

Open the page in your app, signed in as a customer.

GoRunner inside the page, open on Workflows, with No workflows yet and the New workflow button.

You should see GoRunner in your page, open on Workflows, in the customer’s own account.

6.Make the customer’s first workflow

  1. In the embed, open Connections and add a connection to an app that takes an API key.
  2. Open Workflows and press New workflow.

Gmail and the other Google apps need your Google OAuth app first: see Show your name on the sign-in.

To give every customer the same ready-made workflows from your server, use Templates for customers.

Next

Checked against 12d85b3b