← Back to editor

Practical diagram guide

Share URL API: build mermaid.tools links from your own data

Updated

Generate a mermaid.tools link from org chart records or any diagram data. URL format, state payload fields, JavaScript and Python examples, and read-only embeds.

How a share link carries a diagram

Every diagram in mermaid.tools can travel inside its own URL. There is no API key, no account and no server-side document: the editor reads the diagram out of the address bar when the page loads.

A link has three parts.

https://www.mermaid.tools/#state=N4IgbiBcCMA0IGMD2ATAplEAzANkg7g...
<------ editor ------><- key -><--------- payload --------->

The payload is a JSON object describing the editor state, compressed with LZ-String through compressToEncodedURIComponent. That function emits only characters that are already URL-safe, so the result needs no further encoding. Because the payload sits in the URL fragment, after the #, browsers never send it to the server.

Reading a link back is the same two steps in reverse: take everything after #state=, run decompressFromEncodedURIComponent, then parse the JSON.

The state payload

Only code is required. Anything you leave out keeps the editor default, so the smallest useful payload is {"v":1,"code":"flowchart TB\n A --> B"}. Unknown keys are ignored, and a value of the wrong type falls back to the default instead of failing the load.

KeyTypeWhat it sets
vnumberPayload version. Send 1.
codestringThe Mermaid source. This is the diagram.
typestringDiagram keyword for the toolbar picker, such as flowchart, sequenceDiagram, erDiagram or gantt.
themestringOne of default, dark, forest, neutral, base, high-contrast, sepia, monokai, solarized-light, solarized-dark, dracula, nord.
dirstringLayout direction override: TB, BT, LR, RL or TD.
engstringLayout engine, dagre or elk.
spobjectSpacing in pixels, with the keys rank, node, edge, subgraph, padding and margin.
cvstringEdge curve, such as basis, linear or step.
ctobjectCustom Mermaid theme variables, for example {"primaryColor":"#dbeafe"}. Overrides theme.
cnobjectCanvas background: bg (grid, lines, blueprint, solid or none), plus bgColor and gridSize.
vebooleanOpen with visual edit mode already on.
hlbooleanOpen with the hybrid org layout on.
hdnumberManager depth used by the hybrid layout.

Turn your records into org chart source

An org chart is a flowchart whose arrows run from a manager to a report. Two passes over your employee table are enough: declare every person, then draw every reporting line.

Derive each node identifier from a stable primary key rather than from the display name. Renaming someone then leaves the chart wired the same way, and two people who share a name stay separate. An identifier may contain only letters, digits and underscores.

flowchart TB
  n1["Dana Whitfield<br/>Chief Executive"]
  n2["Sam Okafor<br/>VP Engineering"]
  n3["Lena Bright<br/>VP Finance"]
  n1 --> n2
  n1 --> n3

Labels sit inside double quotes, so a quotation mark in someone's name has to be written as &quot;. A <br/> starts a second line, which is how a job title goes under a name. The same shape covers any hierarchy: a category tree, a bill of materials, a folder listing.

Build a link in JavaScript

Install lz-string from npm. This code runs unchanged in Node and in the browser.

import LZString from 'lz-string';

const EDITOR = 'https://www.mermaid.tools/';

const nodeId = key => 'n' + String(key).replace(/[^A-Za-z0-9_]/g, '_');
const label = text => String(text).replace(/&/g, '&amp;').replace(/"/g, '&quot;');

function orgChartSource(people, dir = 'TB') {
  const lines = [`flowchart ${dir}`];
  for (const p of people) lines.push(`  ${nodeId(p.id)}["${label(p.name)}<br/>${label(p.title)}"]`);
  for (const p of people) if (p.managerId) lines.push(`  ${nodeId(p.managerId)} --> ${nodeId(p.id)}`);
  return lines.join('\n');
}

function shareUrl(code, options = {}) {
  const payload = { v: 1, code, type: 'flowchart', ...options };
  return EDITOR + '#state=' + LZString.compressToEncodedURIComponent(JSON.stringify(payload));
}

const people = [
  { id: 'e1', name: 'Dana Whitfield', title: 'Chief Executive', managerId: null },
  { id: 'e2', name: 'Sam Okafor',     title: 'VP Engineering',  managerId: 'e1' },
  { id: 'e3', name: 'Lena Bright',    title: 'VP Finance',      managerId: 'e1' },
];

console.log(shareUrl(orgChartSource(people), { theme: 'forest' }));

To read a link your platform received, reverse the two steps.

const payload = new URL(link).hash.replace(/^#state=/, '');
const state = JSON.parse(LZString.decompressFromEncodedURIComponent(payload));
console.log(state.code);

Build a link in Python

Install the lzstring package, a port of the same algorithm. Use compact JSON separators so the payload stays short.

import json, re
from lzstring import LZString

EDITOR = "https://www.mermaid.tools/"

def node_id(key):
    return "n" + re.sub(r"[^A-Za-z0-9_]", "_", str(key))

def label(text):
    return str(text).replace("&", "&amp;").replace('"', "&quot;")

def org_chart_source(people, direction="TB"):
    lines = [f"flowchart {direction}"]
    for p in people:
        lines.append(f'  {node_id(p["id"])}["{label(p["name"])}<br/>{label(p["title"])}"]')
    for p in people:
        if p.get("manager_id"):
            lines.append(f"  {node_id(p['manager_id'])} --> {node_id(p['id'])}")
    return "\n".join(lines)

def share_url(code, **options):
    payload = {"v": 1, "code": code, "type": "flowchart", **options}
    body = json.dumps(payload, separators=(",", ":"), ensure_ascii=False)
    return EDITOR + "#state=" + LZString().compressToEncodedURIComponent(body)

people = [
    {"id": "e1", "name": "Dana Whitfield", "title": "Chief Executive", "manager_id": None},
    {"id": "e2", "name": "Sam Okafor", "title": "VP Engineering", "manager_id": "e1"},
    {"id": "e3", "name": "Lena Bright", "title": "VP Finance", "manager_id": "e1"},
]

print(share_url(org_chart_source(people), theme="forest"))

Any language with an LZ-String implementation works the same way. The whole contract is: build the JSON, run compressToEncodedURIComponent, prefix #state=.

Embed a read-only diagram

Adding ?ro=1 before the fragment opens the editor in read-only mode. The source becomes uneditable, the diagram-type picker is disabled, the side panels stay collapsed and autosave is off. Panning and zooming still work.

https://www.mermaid.tools/?ro=1#state=N4IgbiBcCMA0IGMD2ATAplEAzANkg7g...

That is the form to put in an iframe when a diagram should appear inside your own product.

<iframe src="https://www.mermaid.tools/?ro=1#state=N4IgbiBcCMA0..."
        width="800" height="600" frameborder="0"
        title="Reporting structure"></iframe>

Regenerate the src whenever the underlying data changes and the embed follows along. If you need a static image rather than a live editor, open the link and export SVG or PNG, or render the same Mermaid source with the Mermaid library on your own side.

Limits, escaping and privacy

Length. The payload grows with the diagram. Repetitive Mermaid source compresses well, but the editor warns above roughly 8,000 characters because some browsers, proxies and chat clients truncate long URLs. For a very large chart, send the .mmd source instead and let the recipient open it with File then Open.

Escaping. Escape & and " inside labels, as the examples above do. Keep node identifiers to letters, digits and underscores. Avoid a bare lowercase end as a label, because Mermaid reads it as a keyword.

Validate before you send. A payload that produces invalid Mermaid still builds a link; the error appears only when someone opens it. Render the source once on your side, or open one generated link yourself, before wiring the generator into a production flow.

Privacy. The fragment is not sent to the mermaid.tools server, but the link itself is the diagram. Anyone who receives it can read the contents, and a link pasted into a chat or a ticket keeps working for as long as it exists. Keep confidential org data out of links shared outside your organisation.

Stability. The v field marks the payload version. Send 1. If a future version changes the shape, links that declare version 1 keep working.

Try it in the editor

Edit this small team reporting structure in Mermaid, inspect the rendered result, and adapt the working source for your own documentation.

flowchart TB
  Lead[Team lead] --> Engineering[Engineering]
  Lead --> Design[Design]
  Lead --> Operations[Operations]
  Engineering --> Frontend[Frontend]
  Engineering --> Backend[Backend]
Open this example Download .mmd

Opening the example lets you review it before replacing your current diagram.

Syntax reference: official Mermaid documentation.

Keep exploring