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 in | What you get | Account or key | Main limits |
|---|---|---|---|
| Studio Embed this figure dialog | An <iframe> snippet and a Markdown link for the open figure | None (the Studio opens on every plan, even signed out); viewers need nothing | URL warning past about 8,000 bytes |
| Weave Embed this flow dialog | An embed link, <iframe> snippet and Markdown link for the board | A signed-in account on Starter or above, to open Weave; viewers need nothing | Links over 65,536 characters do not load; warning past about 8,000 bytes |
/embed URL | A responsive, read-only diagram in any iframe | None | Inline source up to 256 KB; the engine's own rendering budget |
embed.js script | Turns data-glyph elements on your page into embeds | None | As for /embed |
Live source (src / data-src) | An embed that redraws from a file in a repository on every page load | None | Five allowed hosts; 256 KB; 15-second timeout |
POST /api/render | An SVG or PNG file from diagram source | An 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/og | A 1200 × 630 social preview card | None | 200 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.
- 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.
- 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."
- 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."
- Under iframe — Notion, Confluence, any HTML page, click Copy iframe. You see "iframe snippet copied".
- 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 &, as HTML requires inside an attribute):
<iframe src="https://www.flowss.ai/embed?engine=mermaid&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 &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'ssrc="…", because the iframe version has&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 #.
- Open the dialog from the Share button's Embed row ("An iframe or Markdown snippet"), or ⌘K Embed — iframe / Markdown snippet.
- 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."
- 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".
- 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
/embedURL yourself with the engineglyphscriptand 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
| Parameter | Required | Default | Meaning |
|---|---|---|---|
engine | No | mermaid | The engine id, as listed on /docs/engines. A missing id, or one flowss does not recognise, is drawn as Mermaid |
code | One of code or src | None | The diagram source, encoded as URL-safe base64 of its UTF-8 bytes (see below). Up to 256 KB of encoded text |
src | One of code or src | None | An https address of a raw source file on an allowed host, fetched live (see Live source). If both are given, src wins |
theme | No | light | dark for the dark theme; any other value is light |
chrome | No | Shown | 0 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= | No | First declared view | For 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
| Rule | Detail |
|---|---|
| Allowed hosts | raw.githubusercontent.com, gist.githubusercontent.com, gitlab.com, bitbucket.org, codeberg.org |
| Protocol | https only |
| GitHub page links | A github.com/owner/repo/blob/branch/path address is rewritten to its raw file automatically |
| Cross-origin | The visitor's browser fetches the file directly, so the host must allow cross-origin reads |
| Size | Up to 256 KB. A larger file is refused, not drawn cut short |
| Time | The 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.
| Engines | How 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 below | In the visitor's browser |
| Mermaid, Vega-Lite, Vega, Plotly, Graphviz (DOT), D2, Raw SVG, LaTeX (KaTeX), Markmap (Markdown), Nomnoml | In 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 |
| PlantUML | Through 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-->B-->C</pre>
<div data-glyph="d2"
data-src="https://raw.githubusercontent.com/owner/repo/main/docs/arch.d2"></div>
| Attribute | Default | Meaning |
|---|---|---|
data-glyph | Required | The 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-code | The element's text | The source, if you would rather not put it in the element's body |
data-src | None | A raw source address to render live (same hosts and rules as src) |
data-theme | Light | light or dark |
data-height | 420 | The iframe height: a bare number is pixels, or give any CSS length such as 60vh |
data-chrome | Shown | 0 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<,>and&, as in the Mermaid example above. - Elements with neither source text nor
data-srcare left alone. - Each element is processed once and marked, so running it again is safe.
Note: Load the script withdefer, as above, rather thanasyncor 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 withasyncor a plain tag), it can lose that and point the frames at your own site's/embedaddress 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 toenhancehappens 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 fullhttps://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.
| Caller | Daily allowance | Counted per |
|---|---|---|
| With an API key | 60 renders, on every plan | Your 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 plan | Your account |
| No key and no session | None: 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:
| Field | Type | Default | Meaning |
|---|---|---|---|
engine | string | Required | An engine id the API supports (see below) |
code | string | Required | The diagram source, up to 100,000 characters |
format | string | svg | svg or png; any other value gives SVG |
theme | string | light | light or dark; any other value gives light |
width | number | 1200 | PNG only: the width in pixels, clamped to 200–4000 |
The whole request body may be up to about 1 MB.
Responses
| Status | Body | When |
|---|---|---|
| 200 | image/svg+xml | SVG requested. Sent as a download named <engine>.svg |
| 200 | image/png | PNG requested. Named <engine>.png; on a dark theme the background is near-black (#070612), otherwise white |
| 400 | JSON { "error": "Invalid JSON body" } | The body is not a JSON object |
| 400 | JSON { "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 |
| 400 | JSON { "error": "Missing 'code' (diagram source)." } | No source |
| 400 | JSON with code: "needs-browser" or "needs-render-service" | The engine exists but the API cannot draw it (see below) |
| 401 | JSON { "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 |
| 401 | JSON with code: "bad-api-key" | The key is mistyped, revoked or expired |
| 402 | JSON with code: "engine-plan" | A paid workstation's engine (glyphscript) on the Free plan |
| 403 | JSON { "error": "Cross-site request blocked." … } | A session request from another site |
| 413 | JSON { "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 |
| 413 | JSON { "error": "Source is too large (>100 KB). Render a subset or self-host." } | code is over 100,000 characters |
| 413 | JSON with code: "raster-too-large" and width, height, maxPixels | A PNG would exceed 16.8 megapixels even at the drawing's own size; request SVG |
| 422 | JSON with code: "render-failed" | The engine could not draw the source; the message says why |
| 422 | JSON with code: "rasterise-failed" | The SVG could not be turned into a PNG |
| 429 | JSON with code: "ip-cap" or "user-cap" | The daily allowance is used up |
| 500 | JSON with code: "registry-inconsistent" | A fault on the flowss side; please report it |
| 503 | JSON with code: "plan-unavailable" | Your plan could not be read just then, for a paid workstation's engine; try again |
Response headers worth reading:
| Header | Meaning |
|---|---|
Cache-Control | private, 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-Warning | On a PNG drawn narrower than asked because the requested width would exceed 16.8 megapixels |
X-Quota-Remaining | On a signed-in 429 |
X-Quota-Used, X-Quota-Cap | On 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:
| Code | Engines | Why |
|---|---|---|
needs-browser | Mermaid, 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-service | PlantUML and the Kroki engines: bytefield, structurizr, svgbob, erd, excalidraw, wireviz, ditaa, symbolator, nwdiag, packetdiag, pikchr | They 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
| Parameter | Limit | Meaning |
|---|---|---|
title | 200 characters | The headline; without it, the flowss tagline |
subtitle | 300 characters | The line under the headline |
engine | 40 characters | A 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=darkfor 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=0ordata-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.jsuses 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
.txtsources to SVG gives you images that work in READMEs and PDFs, where iframes do not. - Read
GET /api/renderin 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
srcembeds 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
codeover 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=0is 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.jsmust be loaded withdeferto point its frames at flowss reliably, and a laterenhancecall 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/renderfor automation.
Troubleshooting
| Message or symptom | Cause | Fix |
|---|---|---|
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 KB | Re-encode the source as URL-safe base64; shorten it, or use src |
| The embed draws a Mermaid error for a non-Mermaid diagram | The engine id is misspelt, so the viewer fell back to Mermaid | Use the exact id from /docs/engines |
| Spaces or broken characters in the drawn source | Standard base64 with + was used in the address | Use the URL-safe alphabet (- and _) |
| "… renders in the full studio" | The viewer does not carry that engine | Use 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 browser | Split 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 hosts | Move the file to an allowed host, or use code |
| "HTTP 404" (or another status) | The live source address is wrong or private | Open 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 KB | Split the diagram into smaller files |
| "The source host did not answer within 15 s." | The host was too slow | Try again; if it persists, use a faster host or code |
| "Failed to fetch" or a similar network message | The host does not allow cross-origin reads | Use 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 limit | Copy 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 join | Open flowss and join the session there |
| "No view named "…" in this document. Declared: …" | The #view= id does not exist | Use one of the declared ids listed in the message |
| The embed is blank on a page that blocks iframes | The host page does not allow third-party frames | Ask 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" page | The 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 engine | Check the id against GET /api/render |
needs-browser or needs-render-service | The API cannot draw this engine on the server | Render in the Studio and export, or embed with /embed |
render-failed (422) | The source has an error | Open the source in the Studio to see the engine's message in context |
raster-too-large (413) | The PNG would exceed 16.8 megapixels | Request format: "svg", or render a smaller part |
| The PNG is narrower than requested | The requested width would exceed the pixel limit | Read 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 sent | Create a key under Account → API keys and send it as Authorization: Bearer glyp_… |
bad-api-key (401) | The key is mistyped, revoked or expired | Create a new key and update your CI secret |
engine-plan (402) | A Lab (glyphscript) render on the Free plan | Upgrade to Starter, or render a Studio engine |
| "Daily render quota reached for your plan (60/day on free). …" | Your account's allowance is used up | Wait until midnight UTC; the allowance is the same on every plan |
The browser blocks a fetch to /api/render from your site | The API sends no CORS headers | Call it from your server or build step |
| "OG render limit reached (200/day per IP)." | Too many new preview cards from one address | Reuse card addresses so the cache serves them |
