Skip to content

Guides & reference

Embedding and the render API

Embed live diagrams with iframes, embed.js and repository sources, and render SVG or PNG on the server with POST /api/render and an API key.
Sculptural study of connected forms and structured ideas

An exported file is a copy: it stops changing the moment you download it. An embed stays live. flowss gives you three ways to put diagrams into other places without copying pictures around: an embed dialog in the Studio and Weave that hands you a ready-made <iframe> or Markdown snippet; the /embed viewer and its one-line script, embed.js, which you can drive yourself from any web page, including from a source file kept in a Git repository; and the headless render API, POST /api/render, which turns diagram source into an SVG or PNG file on the server for CI pipelines, documentation builds and back-end jobs. This page is the complete reference for all three, with every parameter, limit, response and message. For downloading files from a studio, see Exporting your work.

At a glance

Way inWhat you getAccount or keyMain limits
Studio Embed this figure dialogAn <iframe> snippet and a Markdown link for the open figureNone (the Studio opens on every plan, even signed out); viewers need nothingURL warning past about 8,000 bytes
Weave Embed this flow dialogAn embed link, <iframe> snippet and Markdown link for the boardA signed-in account on Starter or above, to open Weave; viewers need nothingLinks over 65,536 characters do not load; warning past about 8,000 bytes
/embed URLA responsive, read-only diagram in any iframeNoneInline source up to 256 KB; the engine's own rendering budget
embed.js scriptTurns data-glyph elements on your page into embedsNoneAs for /embed
Live source (src / data-src)An embed that redraws from a file in a repository on every page loadNoneFive allowed hosts; 256 KB; 15-second timeout
POST /api/renderAn SVG or PNG file from diagram sourceAn API key (or a signed-in session)60 renders a day; built-in-renderer engines only; Lab, BPMN and Weave engines need Starter; source up to 100 KB; PNG up to 16.8 megapixels
GET /api/ogA 1200 × 630 social preview cardNone200 new cards a day per network address

Embedding from a studio

The Studio: Embed this figure

The Studio builds an embed for whichever figure is open.

  1. Open the dialog in any of three ways: the Share button's Embed… row ("An iframe or Markdown snippet"), ⋮ → Send to ▸ Embed — copy iframe / Markdown snippet, or ⌘K and the same name.
  2. The dialog, Embed this figure, explains what the link carries: "The URL carries the whole diagram in its query string — it renders live with no account, anywhere an iframe or a link works (Notion, Confluence, blogs, READMEs). We keep no copy, but the source travels to our servers on every render and can appear in our access logs and the host page's."
  3. If the URL is longer than about 8,000 bytes, an amber warning appears before you copy anything: "This embed URL is 12,345 bytes — beyond ~8,000 many hosts truncate or refuse URLs, which breaks the embed silently. Trim the diagram source if the paste target mangles it."
  4. Under iframe — Notion, Confluence, any HTML page, click Copy iframe. You see "iframe snippet copied".
  5. Under Markdown — READMEs & docs (a link, not an image), click Copy Markdown. You see "Markdown snippet copied".

The iframe snippet looks like this (the & between parameters is written &amp;, as HTML requires inside an attribute):

<iframe src="https://www.flowss.ai/embed?engine=mermaid&amp;code=Z3JhcGggVEQKICBBLS0-Qg" width="100%" height="480" style="border:0;border-radius:12px;" loading="lazy" allowfullscreen></iframe>

The Studio's snippet sets no theme, so the embed draws in the light theme; add &amp;theme=dark inside the src for a dark page (see the parameter reference below). The address points at whichever flowss site you copied it from.

The Markdown snippet is a link whose text is the figure's title (or "View diagram" for an untitled figure):

[Checkout flow](https://www.flowss.ai/embed?engine=mermaid&code=Z3JhcGggVEQKICBBLS0-Qg)

It is a link and not an image on purpose: GitHub and most Markdown renderers will not display an iframe, and there is no image address for a live embed. To show a picture in a README, export an SVG or PNG and commit it, or render one in CI with the render API below.

The snippet is a snapshot of the source at the moment you copy it. Edit the figure later and the embed does not change; copy a fresh snippet. To keep an embed in step with a file you edit elsewhere, use a live source (see below).

Tip: Some tools take a URL rather than HTML. In a Notion embed block, for example, paste the bare address: copy it from the Markdown snippet (the part in round brackets), not from the iframe's src="…", because the iframe version has &amp; where a plain address needs &, and pasted as a URL it would lose the diagram.

Weave: Embed this flow

Weave embeds the whole board in the link itself, after a #.

  1. Open the dialog from the Share button's Embed row ("An iframe or Markdown snippet"), or ⌘K Embed — iframe / Markdown snippet.
  2. Embed this flow says: "The URL carries the whole flow in its #fragment — no account, no server copy, and the fragment never appears in server logs."
  3. The dialog shows Embed link — N bytes with Copy link, then iframe — Notion, Confluence, any HTML page with Copy iframe, then Markdown — READMEs & docs (a link, not an image) with Copy Markdown. The Markdown link text is "Weave diagram".
  4. Size warnings appear before the snippets. Past about 8,000 bytes: "embed URL is … bytes — beyond ~8,000 many hosts truncate or refuse URLs, which breaks the embed silently. Trim the document, or share a live session (the URL then carries only a room id)." Past 65,536 characters the dialog still shows the link but warns that it will not work: "… past the 65,536-char token cap, so it will NOT load anywhere (even our own parser refuses it). Share a live session or trim the document."

Each Copy button confirms with "Embed link copied", "iframe snippet copied" or "Markdown snippet copied". The dialog is a snapshot of the board at the moment you open it; close and reopen it after editing. Weave links are compressed when that makes them shorter. The embed shows a read-only drawing of the board: ellipses and circles, diamonds, and every other shape as a rounded rectangle, each with its label and colours, joined by its connectors. It shows the first 1,500 shapes and 3,000 connectors. Advanced figures, icons and rich content are simplified to these outlines; for the full picture, export a PNG or SVG instead.

Other studios

The other studios do not have an embed dialog today. You can still embed:

  • A Lab document, by building a /embed URL yourself with the engine glyphscript and the FlowScript source (see the parameter reference). Add #view=<view id> to show one particular view.
  • Any Studio engine, by building the URL or using embed.js.

The /embed viewer can also display read-only drawings of Sketch boards, BPMN diagrams and Figure compositions carried in the same # token format that Weave uses, but no studio creates those links yet.

The /embed URL

/embed is a viewer page built to live inside an iframe. It draws one diagram, fills the frame, and has a transparent background so the host page's colour shows through. Anyone can view an embed without an account.

Parameters

ParameterRequiredDefaultMeaning
engineNomermaidThe engine id, as listed on /docs/engines. A missing id, or one flowss does not recognise, is drawn as Mermaid
codeOne of code or srcNoneThe diagram source, encoded as URL-safe base64 of its UTF-8 bytes (see below). Up to 256 KB of encoded text
srcOne of code or srcNoneAn https address of a raw source file on an allowed host, fetched live (see Live source). If both are given, src wins
themeNolightdark for the dark theme; any other value is light
chromeNoShown0 hides the "Made in flowss" credit at the bottom, for the Studio's own engines only. A figure from a paid workstation (the Lab's glyphscript, bpmn, lucidflow for Weave, and Figure and Weave # links) always shows the credit as Made in flowss · <Studio>, and chrome=0 is ignored
#view=NoFirst declared viewFor glyphscript (Lab) only: the id of the view to draw, added after # at the end of the URL

Example, dark theme with no credit:

https://www.flowss.ai/embed?engine=mermaid&code=Z3JhcGggVEQKICBBLS0-Qg&theme=dark&chrome=0

The credit line reads Made in flowss with an arrow (Made in flowss · Lab, · BPMN, · Weave or · Figure for a paid workstation's figure); it opens the flowss home page in a new tab and does not pass the embed's address on. The embed cannot know who is viewing it, so the credit rule follows the engine rather than anyone's plan.

Encoding the source

code is the source's UTF-8 bytes in base64, using the URL-safe alphabet (- and _ in place of + and /), with the trailing = padding removed. The viewer also accepts standard base64, but a + in a query string is read as a space by many tools, so always use the URL-safe form.

In Node.js:

function embedUrl(engine, source, { theme = "light", chrome = true } = {}) {
  const code = Buffer.from(source, "utf8").toString("base64url");
  const params = new URLSearchParams({ engine, code, theme });
  if (!chrome) params.set("chrome", "0");
  return `https://www.flowss.ai/embed?${params}`;
}

console.log(embedUrl("mermaid", "graph TD\n  A-->B"));
// https://www.flowss.ai/embed?engine=mermaid&code=Z3JhcGggVEQKICBBLS0-Qg&theme=light

In a browser:

function toBase64Url(text) {
  const bytes = new TextEncoder().encode(text);
  let binary = "";
  for (const b of bytes) binary += String.fromCharCode(b);
  return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}

In Python:

import base64
from urllib.parse import urlencode

def embed_url(engine, source, theme="light", chrome=True):
    code = base64.urlsafe_b64encode(source.encode("utf-8")).decode("ascii").rstrip("=")
    params = {"engine": engine, "code": code, "theme": theme}
    if not chrome:
        params["chrome"] = "0"
    return "https://www.flowss.ai/embed?" + urlencode(params)

In a shell:

code=$(printf '%s' "$SOURCE" | base64 | tr '+/' '-_' | tr -d '=\n')
echo "https://www.flowss.ai/embed?engine=d2&code=${code}&theme=dark"

Showing one Lab view

A FlowScript document can declare several views (a flow diagram, a forest plot, a table and so on). The embed draws the first declared view unless the URL ends with #view=<view id>:

https://www.flowss.ai/embed?engine=glyphscript&code=…#view=forest

The view ids are the file names used by the Lab's Export all views (ZIP). Naming a view that does not exist is an error rather than a silent fallback: "No view named "forest" in this document. Declared: consort, table."

Live source from a repository

With src in place of code, the visitor's browser fetches the source file each time the page loads, so the embed always shows the latest committed version.

https://www.flowss.ai/embed?engine=d2&src=https://raw.githubusercontent.com/owner/repo/main/docs/arch.d2
RuleDetail
Allowed hostsraw.githubusercontent.com, gist.githubusercontent.com, gitlab.com, bitbucket.org, codeberg.org
Protocolhttps only
GitHub page linksA github.com/owner/repo/blob/branch/path address is rewritten to its raw file automatically
Cross-originThe visitor's browser fetches the file directly, so the host must allow cross-origin reads
SizeUp to 256 KB. A larger file is refused, not drawn cut short
TimeThe file must arrive within 15 seconds

Because the fetch happens in the visitor's browser, a file in a private repository will not load for visitors who cannot read it.

What the embed can draw

The viewer carries a subset of the engines the Studio can draw. Everything else shows a card instead of an error. For a Cytoscape network, for example, the card reads "Cytoscape (Network) renders in the full studio — This engine (cytoscape) needs a heavier renderer than this preview embeds. Click below to open it in the workstation where you can render and edit.", with an Open in workstation link to the diagram in flowss. While a diagram is drawing, the frame shows "Rendering" and the engine's name.

EnginesHow the embed draws them
Every engine with a built-in renderer: DBML, FlowScript (Lab), Sankey, PRISMA, Gantt, timelines, org charts, fishbone, Venn, PERT, kanban, swimlanes, state machines, Wardley maps, Newick trees, WaveDrom and the rest of the list under the render API belowIn the visitor's browser
Mermaid, Vega-Lite, Vega, Plotly, Graphviz (DOT), D2, Raw SVG, LaTeX (KaTeX), Markmap (Markdown), NomnomlIn the visitor's browser. D2 is translated to DOT and laid out by Graphviz, exactly as the Studio does it
3D Molecules (3Dmol)A still image of the molecule
PlantUMLThrough the flowss PlantUML relay, which sends the source to a PlantUML server (the public plantuml.com unless flowss runs its own). Sources up to 30,000 characters
Pikchr, SVGBob (ASCII)Through the flowss relay to Kroki, a third-party render service
Everything else (for example Cytoscape, Excalidraw, BPMN, Weave in the ?engine= form, and the other Kroki engines)The "renders in the full studio" card with Open in workstation

The relayed engines count against daily allowances per visitor network address, because an embed is never signed in (even for a visitor who is signed in to flowss): 300 PlantUML renders a day, and a separate 300 a day shared by the Kroki engines (Pikchr and SVGBob). For pages with heavy traffic, prefer an engine the browser draws itself.

Every engine also has a safe-rendering size budget. Past it the embed shows Render error in followed by the engine's name, with a message such as "Source is 312.5 KB — past the 244.1 KB safe-rendering budget for graphviz. Rendering this in the browser would freeze the page. …". Split the diagram or trim the source; the message also suggests the render API, which helps only for the built-in-renderer engines it draws (not, for example, Graphviz or Mermaid). Any other drawing error shows the same Render error in box with the engine's own message and an Edit link.

Security and privacy of an embed

An embed is designed to be safe to put on any page, including pages you do not control:

  • The viewer runs in a sandbox with no access to flowss cookies, storage or sessions, even for a visitor who is signed in to flowss in the same browser.
  • It cannot navigate or redirect the host page, submit forms or open pop-up dialogs on it. The credit link opens flowss in a new tab.
  • It can be framed by any site; that is what it is for.
  • With the ?code= form, the diagram source is part of the address. It reaches flowss on every view and can appear in server logs and the host page's logs. flowss keeps no copy of it. Weave's # links keep the source out of the request entirely.
  • PlantUML, Pikchr and SVGBob sources are sent on to the render services named above.

Do not embed diagrams that contain secrets, and remember that anyone who sees the page can read the source out of its address.

The embed script: embed.js

embed.js turns marked-up elements on your page into embeds, so you can write diagram source straight into your HTML. It has no dependencies and does no tracking; it builds iframe addresses pointing at the site that served the script, which it reads from its own <script> tag.

<script src="https://www.flowss.ai/embed.js" defer></script>

<div data-glyph="d2" data-theme="dark">
  user -> web: request
  web  -> api: rpc
  api  -> db:  sql
</div>

<pre data-glyph="mermaid">graph TD; A--&gt;B--&gt;C</pre>

<div data-glyph="d2"
     data-src="https://raw.githubusercontent.com/owner/repo/main/docs/arch.d2"></div>
AttributeDefaultMeaning
data-glyphRequiredThe engine id. The attribute marks the element; if it is left empty, data-engine supplies the engine, and with neither the engine is mermaid
data-codeThe element's textThe source, if you would rather not put it in the element's body
data-srcNoneA raw source address to render live (same hosts and rules as src)
data-themeLightlight or dark
data-height420The iframe height: a bare number is pixels, or give any CSS length such as 60vh
data-chromeShown0 hides the "Made in flowss" credit

How it behaves:

  • On page load it replaces the contents of every [data-glyph] element with a full-width iframe (loading="lazy", titled "Flow Systems diagram").
  • Common leading indentation is removed from inline source, so source indented to match your HTML renders correctly. Escape <, > and & in HTML as &lt;, &gt; and &amp;, as in the Mermaid example above.
  • Elements with neither source text nor data-src are left alone.
  • Each element is processed once and marked, so running it again is safe.
Note: Load the script with defer, as above, rather than async or as a plain script tag. The script can only see which site served it while it is first running; if it has to wait for the page to finish loading before converting your elements (which happens with async or a plain tag), it can lose that and point the frames at your own site's /embed address instead, which shows your site's "not found" page.

For content added after the page loads, call enhance on the new part of the page. It returns the number of elements it turned into embeds. The same object is available under two names:

window.FlowSystems.enhance(document.querySelector("#new-section"));
// or, for pages written against the original name:
window.Glyph.enhance(document.querySelector("#new-section"));
Warning: A later call to enhance happens after the script has finished running, so it builds addresses from your page's own site rather than from flowss. On a page that is not served by flowss, insert the <iframe> with a full https://www.flowss.ai/embed?… address yourself for content you add later.

The render API

POST /api/render draws a diagram on the server and returns the file, with no browser involved. Use it from CI, static-site generators, documentation builds and back-end services. It sends no CORS headers, so call it from a server or script rather than from a web page on another site.

Authentication and quotas

The render API needs an API key or a signed-in session. A request with neither is refused with 401 sign-in-required. API keys are free on every plan.

CallerDaily allowanceCounted per
With an API key60 renders, on every planYour account, shared with the REST API's deterministic calls and some in-app actions
Signed in, from a flowss page (same site)60 renders, on every planYour account
No key and no sessionNone: 401—

Allowances reset at midnight UTC. Upgrading does not raise the render allowance. All of your keys share the one account allowance, so making more keys does not add renders.

Engines from paid workstations. The Lab's engine (glyphscript) belongs to a paid workstation, as do BPMN and Weave, which the API does not draw. On the Free plan the API refuses glyphscript with 402 engine-plan; Starter and above render it. Every other engine the API draws renders on every plan.

A flowss deployment with no sign-in configured (self-hosted, for example) works without a key and counts 60 renders a day per network address.

Every POST is counted as soon as it arrives, before the body is read, so a request that is then refused (bad JSON, an unknown engine, an engine the API does not draw, a render error) still uses one render. Check new engines against GET /api/render first, which is free.

Create a key on your account page under API keys with Create key; the full key (it starts glyp_) is shown once. The step-by-step guide is in The REST API. Send it in the Authorization header, either as Bearer glyp_… or as the bare key, or in an X-Api-Key header:

Authorization: Bearer glyp_…
X-Api-Key: glyp_…

A key the server does not recognise (mistyped, revoked or expired) is refused with 401 bad-api-key. A request signed in with a session cookie must come from a flowss page; one from another site is refused with 403.

Request

POST https://www.flowss.ai/api/render with a JSON body:

FieldTypeDefaultMeaning
enginestringRequiredAn engine id the API supports (see below)
codestringRequiredThe diagram source, up to 100,000 characters
formatstringsvgsvg or png; any other value gives SVG
themestringlightlight or dark; any other value gives light
widthnumber1200PNG only: the width in pixels, clamped to 200–4000

The whole request body may be up to about 1 MB.

Responses

StatusBodyWhen
200image/svg+xmlSVG requested. Sent as a download named <engine>.svg
200image/pngPNG requested. Named <engine>.png; on a dark theme the background is near-black (#070612), otherwise white
400JSON { "error": "Invalid JSON body" }The body is not a JSON object
400JSON { "error": "Unknown engine \"x\". GET /api/render for the supported list." }engine is missing, is not a string, or does not name a flowss engine
400JSON { "error": "Missing 'code' (diagram source)." }No source
400JSON with code: "needs-browser" or "needs-render-service"The engine exists but the API cannot draw it (see below)
401JSON { "code": "sign-in-required", "error": "The render API needs a signed-in session or an API key — create a key at /account (API keys).", "docs": "/docs/export-embed" }No key and no session
401JSON with code: "bad-api-key"The key is mistyped, revoked or expired
402JSON with code: "engine-plan"A paid workstation's engine (glyphscript) on the Free plan
403JSON { "error": "Cross-site request blocked." … }A session request from another site
413JSON { "error": "Request body is too large (>977 KB).", "code": "payload-too-large" }The body is over 1,000,000 bytes (about 977 KB). This is checked as the body arrives, so it also applies to a chunked upload with no declared length
413JSON { "error": "Source is too large (>100 KB). Render a subset or self-host." }code is over 100,000 characters
413JSON with code: "raster-too-large" and width, height, maxPixelsA PNG would exceed 16.8 megapixels even at the drawing's own size; request SVG
422JSON with code: "render-failed"The engine could not draw the source; the message says why
422JSON with code: "rasterise-failed"The SVG could not be turned into a PNG
429JSON with code: "ip-cap" or "user-cap"The daily allowance is used up
500JSON with code: "registry-inconsistent"A fault on the flowss side; please report it
503JSON with code: "plan-unavailable"Your plan could not be read just then, for a paid workstation's engine; try again

Response headers worth reading:

HeaderMeaning
Cache-Controlprivate, max-age=60 on every response, with Vary: Authorization, X-Api-Key, Cookie
Content-Security-Policy: sandbox; script-src 'none'On SVG responses: the file can never run as a page
X-Render-Width-Requested, X-Render-Width-Applied, X-Render-Width-WarningOn a PNG drawn narrower than asked because the requested width would exceed 16.8 megapixels
X-Quota-RemainingOn a signed-in 429
X-Quota-Used, X-Quota-CapOn a keyed 429

The 429 message with a key is "Daily render quota reached for your plan (60/day on free). Wait until reset, or self-host for no cap."; signed in, it is "Daily render quota reached (60/day). Wait until reset, or self-host for no cap."

Which engines the API renders

The API draws only engines with a built-in renderer, which run on the server with no browser. Today that is:

anatomy archimate argmap astro attacktree bmc bowtie bullet calendarheatmap
causaldag cfd chess chord choropleth circuit cloudarch dbml dfd dmn drugnet
dsm econ eventstorm faulttree fishbone flamegraph floorplan floorplan3d
freebody funnel gantt glyphscript grafcet kanban ladder logic marimekko music
newick orgchart packet pareto pedigree pert petri phase pianoroll pid plot
prisma quadrant queueing raci rack railroad rbd sankey sequence
serviceblueprint sipoc spaghetti spc statemachine storymap strat swimlane
syntaxtree sysdynamics sysml timeline tournament treemap valuestream venn
wardley waterfall wavedrom wordcloud

New engines are added over time, so read the live list rather than hard-coding this one. Two kinds of engine are refused, each with its own code and a sentence saying where it can be drawn:

CodeEnginesWhy
needs-browserMermaid, Graphviz (DOT), D2, Vega-Lite, Vega, Plotly, Nomnoml, LaTeX (KaTeX), Markmap, 3D Molecules, Cytoscape, Raw SVG, BPMN, Weave and Floor plan (3D WebGL)They draw with a page, a canvas or a WebAssembly viewer. The message points to /studio and /embed, or to the dedicated studio (/bpmn for BPMN, /lucidflow for Weave)
needs-render-servicePlantUML and the Kroki engines: bytefield, structurizr, svgbob, erd, excalidraw, wireviz, ditaa, symbolator, nwdiag, packetdiag, pikchrThey are drawn by a render service outside flowss

For Mermaid, Graphviz and D2 in particular, render in the Studio and export, or embed with /embed.

Discovering capabilities

GET /api/render needs no key (only drawing does; its auth field says "session or API key") and returns a JSON description of the API, including every engine it will draw and every engine it will refuse, with the reason:

{
  "description": "POST { engine, code, format?: 'svg'|'png', theme?: 'light'|'dark', width? } to render a diagram. SVG returned by default. Native engines only in v1.",
  "supported": ["anatomy", "archimate", "argmap", "…"],
  "unsupported": [
    { "engine": "mermaid", "code": "needs-browser", "reason": "Engine \"mermaid\" renders in a browser (a real DOM, a canvas or a WebAssembly viewer) and cannot be drawn by the headless API. Render it client-side via the /studio or /embed routes." }
  ],
  "total": 105,
  "formats": ["svg", "png"],
  "themes": ["light", "dark"],
  "docs": "https://www.flowss.ai/docs/engines"
}

supported plus unsupported always adds up to total, so you can check that the list is complete.

Examples

Render a Sankey diagram to SVG with curl, building the JSON safely with jq:

cat > flows.txt <<'EOF'
title "Revenue to profit"
flow "Revenue" "Cost of goods" 45
flow "Revenue" "Gross profit" 55
flow "Gross profit" "Operating costs" 30
flow "Gross profit" "Operating profit" 25
flow "Operating profit" "Tax" 6
flow "Operating profit" "Net profit" 19
EOF

jq -n --arg code "$(cat flows.txt)" '{engine: "sankey", code: $code, format: "svg"}' \
  | curl -sS -f https://www.flowss.ai/api/render \
      -H "Authorization: Bearer $FLOWSS_KEY" \
      -H "Content-Type: application/json" \
      --data @- -o flows.svg

Render a PNG 1,600 pixels wide in the dark theme with Node.js 18 or later:

import { readFile, writeFile } from "node:fs/promises";

const res = await fetch("https://www.flowss.ai/api/render", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.FLOWSS_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    engine: "sankey",
    code: await readFile("flows.txt", "utf8"),
    format: "png",
    theme: "dark",
    width: 1600,
  }),
});
if (!res.ok) throw new Error((await res.json()).error);
if (res.headers.get("X-Render-Width-Warning")) console.warn(res.headers.get("X-Render-Width-Warning"));
await writeFile("flows.png", Buffer.from(await res.arrayBuffer()));

The same in Python:

import os, requests

with open("flows.txt", encoding="utf-8") as f:
    source = f.read()

r = requests.post(
    "https://www.flowss.ai/api/render",
    headers={"Authorization": f"Bearer {os.environ['FLOWSS_KEY']}"},
    json={"engine": "sankey", "code": source, "format": "png", "width": 1600},
    timeout=60,
)
if r.status_code != 200:
    raise SystemExit(r.json().get("error"))
with open("flows.png", "wb") as out:
    out.write(r.content)

In these examples FLOWSS_KEY is whatever name you give the secret in your own CI system.

Generating a diagram and its embed URL

POST /api/v1/diagram turns a plain-language prompt into diagram source for the best engine and returns a ready embed_url (in the dark theme), which you can drop straight into an iframe. It needs an API key (a call without one is refused with 401), always uses AI, and counts against your account's daily AI allowance. Prompts are limited to 8,000 characters. The full reference is in The REST API.

{
  "engine": "d2",
  "title": "Food delivery — containers",
  "code": "…",
  "embed_url": "https://www.flowss.ai/embed?engine=d2&code=…&theme=dark",
  "links": {
    "embed": "https://www.flowss.ai/embed?engine=d2&code=…&theme=dark",
    "render": "https://www.flowss.ai/api/render"
  }
}

The links.render address is a reminder that you can send the returned code to the render API for a static file, provided the engine is one the render API draws.

Social preview cards

When a flowss link is shared in a chat or a social feed, the preview image comes from GET /api/og. You can use it for your own pages too:

https://www.flowss.ai/api/og?title=Checkout%20flow&subtitle=How%20an%20order%20becomes%20a%20shipment&engine=mermaid
ParameterLimitMeaning
title200 charactersThe headline; without it, the flowss tagline
subtitle300 charactersThe line under the headline
engine40 charactersA small label pill above the headline

Without a title the headline is the flowss tagline, and without a subtitle the line under it names the number of engines and templates. Longer values are cut to the limits above. The response is a 1200 × 630 PNG, cached by the content network for a week (browsers keep it for a day). With none of the three parameters you are redirected to the standard flowss card, which does not count toward any limit. New cards are limited to 200 a day per network address ("OG render limit reached (200/day per IP)."); cards served from the cache do not count.

Tips

  • Pick the theme for the host page. Add &theme=dark for dark sites. Weave's # links follow ?theme= too: put it before the #, as in /embed?theme=dark#g1.….
  • Hide the credit on internal pages with &chrome=0 or data-chrome="0". This works for the Studio's own engines; Lab, BPMN, Weave and Figure figures always show the credit.
  • Set a height that suits the diagram. The Studio snippet uses 480 pixels and embed.js uses 420; wide, short diagrams look better lower, tall ones higher.
  • Keep diagrams in Git and embed them with src. The embed then updates with every commit, and nobody has to copy snippets again.
  • Use the render API in CI for static images. A build step that renders .txt sources to SVG gives you images that work in READMEs and PDFs, where iframes do not.
  • Read GET /api/render in your pipeline before rendering a new engine, so an unsupported engine fails with a clear reason before you ship.
  • Prefer browser-drawn engines for busy pages. PlantUML, Pikchr and SVGBob embeds pass through a relay with a per-visitor daily allowance.

Limits and known constraints

  • Embeds are read-only. Viewers cannot edit, pan with editing tools or comment; Open in workstation opens the diagram in flowss for that.
  • A Studio embed is a snapshot of the source at the time you copied it. Only src embeds update by themselves.
  • Many engines are not drawn by the embed viewer and show the "renders in the full studio" card instead.
  • Weave embeds show simplified outlines of shapes, and at most 1,500 shapes and 3,000 connectors.
  • Addresses longer than about 8,000 characters break in many hosts, chat apps and proxies. Weave links over 65,536 characters do not load at all, and inline code over 256 KB is ignored.
  • Live sources must come from one of five hosts that allow cross-origin reads, over https, under 256 KB, within 15 seconds.
  • The render API draws only built-in-renderer engines. Mermaid, Graphviz, D2, PlantUML and other browser or service engines are refused.
  • The render API needs an API key or a signed-in session; there is no anonymous allowance. The allowance is 60 a day on every plan, and an unrecognised key is refused.
  • On the Free plan the render API refuses the Lab's engine (glyphscript) with 402; Starter and above render it.
  • chrome=0 is ignored for a paid workstation's figure: its embed always shows the credit.
  • Every render request counts toward the allowance, including ones that are then refused for a bad body, an unknown or unsupported engine, or a render error.
  • embed.js must be loaded with defer to point its frames at flowss reliably, and a later enhance call on a page not served by flowss points them at your own site.
  • PNGs from the render API are at most 16.8 megapixels (for example 4,096 × 4,096); larger drawings are drawn narrower or refused.
  • The render API sends no CORS headers; call it from a server or script.
  • The app's own export menus use flowss's internal rasteriser, which is not a public API. Use POST /api/render for automation.

Troubleshooting

Message or symptomCauseFix
The embed shows Pass ?engine=…&code=<base64> (or &src=<raw url>) to embed a diagram.No source, source that is not valid base64, or code over 256 KBRe-encode the source as URL-safe base64; shorten it, or use src
The embed draws a Mermaid error for a non-Mermaid diagramThe engine id is misspelt, so the viewer fell back to MermaidUse the exact id from /docs/engines
Spaces or broken characters in the drawn sourceStandard base64 with + was used in the addressUse the URL-safe alphabet (- and _)
"… renders in the full studio"The viewer does not carry that engineUse Open in workstation, export an image instead, or pick an engine the viewer draws
Render error in (engine name) with "Source is … — past the … safe-rendering budget …"The source is too large to draw in a browserSplit the diagram, or render it with the render API where the engine allows
"That source URL isn't a supported raw code host."src is not https or not one of the five hostsMove the file to an allowed host, or use code
"HTTP 404" (or another status)The live source address is wrong or privateOpen the raw address in a private browser window to check it
"That source is larger than 256 KB, too large to embed — it would be drawn cut short."The live source file is over 256 KBSplit the diagram into smaller files
"The source host did not answer within 15 s."The host was too slowTry again; if it persists, use a faster host or code
"Failed to fetch" or a similar network messageThe host does not allow cross-origin readsUse raw.githubusercontent.com or a gist
"This embed link is damaged or too large."A Weave # link was cut short by a chat app or is over the size limitCopy a fresh link from Embed this flow; trim the board if it is very large
"This embed points at a live session."The link names a live session, which the viewer cannot joinOpen flowss and join the session there
"No view named "…" in this document. Declared: …"The #view= id does not existUse one of the declared ids listed in the message
The embed is blank on a page that blocks iframesThe host page does not allow third-party framesAsk the site owner to allow frames from www.flowss.ai, or use an exported image
embed.js frames show your own site's "not found" pageThe script lost track of the site it was loaded from (an async or plain script tag, or a later enhance call)Load it with defer; for content added later, insert an <iframe> with a full flowss /embed address
"Unknown engine "x". GET /api/render for the supported list."The engine id is not a flowss engineCheck the id against GET /api/render
needs-browser or needs-render-serviceThe API cannot draw this engine on the serverRender in the Studio and export, or embed with /embed
render-failed (422)The source has an errorOpen the source in the Studio to see the engine's message in context
raster-too-large (413)The PNG would exceed 16.8 megapixelsRequest format: "svg", or render a smaller part
The PNG is narrower than requestedThe requested width would exceed the pixel limitRead X-Render-Width-Warning; request SVG for full resolution
sign-in-required (401): "The render API needs a signed-in session or an API key …"No key was sentCreate a key under Account → API keys and send it as Authorization: Bearer glyp_…
bad-api-key (401)The key is mistyped, revoked or expiredCreate a new key and update your CI secret
engine-plan (402)A Lab (glyphscript) render on the Free planUpgrade to Starter, or render a Studio engine
"Daily render quota reached for your plan (60/day on free). …"Your account's allowance is used upWait until midnight UTC; the allowance is the same on every plan
The browser blocks a fetch to /api/render from your siteThe API sends no CORS headersCall it from your server or build step
"OG render limit reached (200/day per IP)."Too many new preview cards from one addressReuse card addresses so the cache serves them

Something unclear or out of date on this page? Tell us from the Support link in any studio — the flowss team reads every report.

© 2026 Voranox Inc. flowss — Flow Systems Studio. All rights reserved.

This documentation, its text and its examples are protected by copyright. Engine and format names are trademarks of their respective owners — see the terms and copyright and licences.