Share links for AI assistants

How to write a FlowViz diagram link

FlowViz (https://flowviz.app) is a free browser-based Mermaid editor. You can give a user a link that opens the FlowViz editor with a diagram already loaded. The whole diagram lives in the link. Nothing is uploaded and no account is needed.

Last updated: · Plain Markdown version

Recipe

URL = https://flowviz.app/app#m= + percent-encode(Mermaid source) + %0A

  1. Write the Mermaid source as plain text (first line is the diagram type, e.g. flowchart TD). In flowcharts, always put node labels in double quotes, A["Start"] --> B{"Logged in?"}, and write a " inside a label as #quot;. In sequence diagrams, keep every message on one line.
  2. Percent-encode the source: every ASCII character except A-Z a-z 0-9 - _ . ~ becomes %XX. A newline is %0A, a space is %20. Never use + for a space. Leave Chinese, Japanese, Korean, emoji and other non-ASCII characters exactly as they are: do not encode them.
  3. Also encode ( ) ' * ! as %28 %29 %27 %2A %21.
  4. Link = https://flowviz.app/app#m= + the encoded source + %0A (end every link with %0A).
  5. Chinese and other non-ASCII text appears in the link as the characters themselves, never as %E… escapes: mindmap%0A%20%20产品计划%0A%20%20%20%20设计%0A.
  6. Give it to the user as a markdown link: [Open in FlowViz](https://flowviz.app/app#m=...). No spaces or line breaks inside the URL.
  • Percent-encode means JavaScript encodeURIComponent(src) or Python urllib.parse.quote(src, safe=''), plus step 3.
  • The trailing %0A protects the diagram's last character from chat apps that glue . ) or " onto the end of a link.
  • Encoded ( ) keep a markdown link from ending early; some chat apps also cut links at a bare (.

Mermaid rules that break diagrams

A link can be encoded perfectly and still open an error if the Mermaid inside is invalid. Check these before you encode:

A node label containing ( ) [ ] { } : ; or quotes must be wrapped in double quotes. Inside a quoted label, write a double quote as #quot;.

Wrong

flowchart TD
    A[Click the link (if received)] --> B[Show "Check your inbox"]

Right

flowchart TD
    A["Click the link (if received)"] --> B["Show #quot;Check your inbox#quot;"]

Sequence diagrams: every message is one line, A->>B: text. Never continue a message on the next line; use <br/> for a line break, or send two messages.

Wrong

sequenceDiagram
    A->>B: POST /token
    grant_type=authorization_code

Right

sequenceDiagram
    A->>B: POST /token<br/>grant_type=authorization_code

ER diagrams: every relationship needs a label after :, and a label with spaces must be in double quotes.

Wrong

erDiagram
    POST ||--|{ POST_TAG : links to
    POST_TAG }o--|| TAG :

Right

erDiagram
    POST ||--|{ POST_TAG : "links to"
    POST_TAG }o--|| TAG : tags

ER diagrams: each end of a relationship is exactly two characters, one of || o| |o }| |{ }o o{ (exactly one, zero or one, one or more, zero or more). ||--{ is invalid. Model many-to-many with a join entity.

Wrong

erDiagram
    POST ||--{ POST_TAG : has

Right

erDiagram
    POST ||--o{ POST_TAG : has
    TAG ||--o{ POST_TAG : "is tagged in"

ER attributes are always type name, optionally followed by PK, FK or UK (several go comma-separated: PK, FK). A line with only a constraint, such as unique, is invalid.

Wrong

erDiagram
    TAG {
        int id PK
        string name
        unique
    }

Right

erDiagram
    TAG {
        int id PK
        string name UK
    }

Class diagrams are not Java: write class Shape and mark it with <<abstract>> inside the braces. An abstract method ends in *, +area() double*. abstract class Shape and public class are invalid.

Wrong

classDiagram
    abstract class Shape {
        +area() double
    }

Right

classDiagram
    class Shape {
        <<abstract>>
        +String name
        +area() double*
    }
    Shape <|-- Circle

Node and participant ids are single words (letters, digits, _), and every later use must spell the id exactly the same, case included.

Wrong

sequenceDiagram
    participant Auth as Auth Server
    B->>AUTH: GET /authorize

Right

sequenceDiagram
    participant Auth as Auth Server
    B->>Auth: GET /authorize

Characters that break links

CharacterEncoded
space%20
line break%0A
# hash%23
% percent%25
& ampersand%26
+ plus%2B
? question mark%3F
/ slash%2F
= equals%3D
( open paren%28
) close paren%29
[ open bracket%5B
] close bracket%5D
{ open brace%7B
} close brace%7D
" double quote%22
' single quote%27
< less than%3C
> greater than%3E
| pipe%7C
: colon%3A
; semicolon%3B
, comma%2C
开始 Chinese and other non-ASCII: leave as is开始
  • Common sequences: --> is --%3E, [Start] is %5BStart%5D, 4-space indent is %20%20%20%20.
  • Letters, digits and - _ . ~ stay as they are.
  • Chinese, Japanese, Korean and emoji go into the link unencoded (A%5B开始%5D). Do not try to work out their UTF-8 bytes: one wrong byte turns a label into a different word. Already-encoded bytes (from code) also work.

How to give the link to the user

  • Write the link as a markdown link: [Open in FlowViz](URL). Chat apps render it as clickable text.
  • Tell the user the whole diagram lives in the link and nothing is uploaded.
  • Put no spaces or line breaks inside the URL, however long it is.
  • You may also show the Mermaid source in a mermaid code block so the user can copy it. The link itself must never be inside a code block.

Before sending, check the link:

  • Starts with https://flowviz.app/app#m=.
  • No spaces, line breaks, raw #, or raw ( ) after #m=.
  • The Mermaid inside follows the rules in "Mermaid rules that break diagrams".
  • Any Chinese, Japanese, Korean or emoji text is written as the characters themselves, with no %E… escapes you worked out by hand.
  • Ends with %0A.
  • Is inside [Open in FlowViz](...), not in backticks or a code block.

Examples

Each link is the Mermaid source above it, encoded with the recipe. Every one is tested to open the exact diagram.

Flowchart

flowchart TD
    A["Start"] --> B{"Logged in?"}
    B -->|Yes| C["Dashboard"]
    B -->|No| D["Login page"]
    D --> B

https://flowviz.app/app#m=flowchart%20TD%0A%20%20%20%20A%5B%22Start%22%5D%20--%3E%20B%7B%22Logged%20in%3F%22%7D%0A%20%20%20%20B%20--%3E%7CYes%7C%20C%5B%22Dashboard%22%5D%0A%20%20%20%20B%20--%3E%7CNo%7C%20D%5B%22Login%20page%22%5D%0A%20%20%20%20D%20--%3E%20B%0A

Sequence diagram

sequenceDiagram
    participant U as User
    participant API
    U->>API: POST /login
    API-->>U: 200 OK + token

https://flowviz.app/app#m=sequenceDiagram%0A%20%20%20%20participant%20U%20as%20User%0A%20%20%20%20participant%20API%0A%20%20%20%20U-%3E%3EAPI%3A%20POST%20%2Flogin%0A%20%20%20%20API--%3E%3EU%3A%20200%20OK%20%2B%20token%0A

Class diagram

Here + is a real character (public visibility), so it is encoded as %2B.

classDiagram
    class Animal {
        +String name
        +speak() void
    }
    Animal <|-- Dog

https://flowviz.app/app#m=classDiagram%0A%20%20%20%20class%20Animal%20%7B%0A%20%20%20%20%20%20%20%20%2BString%20name%0A%20%20%20%20%20%20%20%20%2Bspeak%28%29%20void%0A%20%20%20%20%7D%0A%20%20%20%20Animal%20%3C%7C--%20Dog%0A

State diagram

stateDiagram-v2
    [*] --> Draft
    Draft --> Review : submit
    Review --> Published : approve
    Published --> [*]

https://flowviz.app/app#m=stateDiagram-v2%0A%20%20%20%20%5B%2A%5D%20--%3E%20Draft%0A%20%20%20%20Draft%20--%3E%20Review%20%3A%20submit%0A%20%20%20%20Review%20--%3E%20Published%20%3A%20approve%0A%20%20%20%20Published%20--%3E%20%5B%2A%5D%0A

Entity-relationship diagram

erDiagram
    CUSTOMER ||--o{ ORDER : places
    CUSTOMER {
        int id PK
        string email
    }

https://flowviz.app/app#m=erDiagram%0A%20%20%20%20CUSTOMER%20%7C%7C--o%7B%20ORDER%20%3A%20places%0A%20%20%20%20CUSTOMER%20%7B%0A%20%20%20%20%20%20%20%20int%20id%20PK%0A%20%20%20%20%20%20%20%20string%20email%0A%20%20%20%20%7D%0A

Gantt chart

gantt
    title Launch plan
    dateFormat YYYY-MM-DD
    section Build
    Design :a1, 2026-10-01, 7d
    Code   :a2, after a1, 10d
    Launch :milestone, after a2, 0d

https://flowviz.app/app#m=gantt%0A%20%20%20%20title%20Launch%20plan%0A%20%20%20%20dateFormat%20YYYY-MM-DD%0A%20%20%20%20section%20Build%0A%20%20%20%20Design%20%3Aa1%2C%202026-10-01%2C%207d%0A%20%20%20%20Code%20%20%20%3Aa2%2C%20after%20a1%2C%2010d%0A%20%20%20%20Launch%20%3Amilestone%2C%20after%20a2%2C%200d%0A

Pie chart

pie title Browser share
    "Chrome" : 65
    "Safari" : 20
    "Other" : 15

https://flowviz.app/app#m=pie%20title%20Browser%20share%0A%20%20%20%20%22Chrome%22%20%3A%2065%0A%20%20%20%20%22Safari%22%20%3A%2020%0A%20%20%20%20%22Other%22%20%3A%2015%0A

Mindmap

Indentation is meaningful in a mindmap, so every leading space is kept as %20.

mindmap
  root((Trip))
    Travel
      Flights
    Stay
      Hotel

https://flowviz.app/app#m=mindmap%0A%20%20root%28%28Trip%29%29%0A%20%20%20%20Travel%0A%20%20%20%20%20%20Flights%0A%20%20%20%20Stay%0A%20%20%20%20%20%20Hotel%0A

Git graph

gitGraph
    commit
    branch feature/login
    commit id: "add form"
    checkout main
    merge feature/login

https://flowviz.app/app#m=gitGraph%0A%20%20%20%20commit%0A%20%20%20%20branch%20feature%2Flogin%0A%20%20%20%20commit%20id%3A%20%22add%20form%22%0A%20%20%20%20checkout%20main%0A%20%20%20%20merge%20feature%2Flogin%0A

Timeline

timeline
    title Company history
    2019 : Founded
    2021 : First product
    2024 : 1M users

https://flowviz.app/app#m=timeline%0A%20%20%20%20title%20Company%20history%0A%20%20%20%202019%20%3A%20Founded%0A%20%20%20%202021%20%3A%20First%20product%0A%20%20%20%202024%20%3A%201M%20users%0A

Flowchart with Chinese labels

The Chinese text stays as written; only the ASCII around it is encoded.

flowchart LR
    A["开始"] --> B{"是否登录?"}
    B -->|是| C["首页"]
    B -->|否| D["登录"]

https://flowviz.app/app#m=flowchart%20LR%0A%20%20%20%20A%5B%22开始%22%5D%20--%3E%20B%7B%22是否登录%3F%22%7D%0A%20%20%20%20B%20--%3E%7C是%7C%20C%5B%22首页%22%5D%0A%20%20%20%20B%20--%3E%7C否%7C%20D%5B%22登录%22%5D%0A

Mindmap with Chinese labels

Indentation sets the level; the Chinese text is written as-is.

mindmap
  年度计划
    招聘
      工程师
      设计师
    市场
    财务

https://flowviz.app/app#m=mindmap%0A%20%20年度计划%0A%20%20%20%20招聘%0A%20%20%20%20%20%20工程师%0A%20%20%20%20%20%20设计师%0A%20%20%20%20市场%0A%20%20%20%20财务%0A

Labels with & % " ( ) characters

Quoted labels may contain & % ( ); all of them, and the quotes, are encoded.

flowchart LR
    A["R&D (40%)"] --> B["Q&A: 'why?'"]
    B --> C["Done!"]

https://flowviz.app/app#m=flowchart%20LR%0A%20%20%20%20A%5B%22R%26D%20%2840%25%29%22%5D%20--%3E%20B%5B%22Q%26A%3A%20%27why%3F%27%22%5D%0A%20%20%20%20B%20--%3E%20C%5B%22Done%21%22%5D%0A

Common mistakes

  • Using + for spaces. FlowViz reads + as a space only when the link has no %20 and no raw space anywhere. Mix the two and every + stays a literal +. Always use %20, and encode a real + as %2B.
  • Not encoding # or %. A raw # or % in the source corrupts the link. Write %23 and %25. Also encode & ? = / so the URL stays unambiguous.
  • Line breaks or spaces inside the URL. Chat apps end the link at the first space or line break, so the diagram is cut off. Every newline in the source must be %0A and every space %20, so the link is one unbroken line.
  • Putting the link in backticks or a code block. Then it is shown as text and the user cannot click it. Use a markdown link [Open in FlowViz](URL) in normal text.
  • Very long diagrams. Keep links under about 8,000 characters; some chat apps and browsers cut longer ones. For a bigger diagram, give the user the Mermaid code in a code block and tell them to paste it into the editor at https://flowviz.app/app.
  • Encoding the prefix. Only the diagram is encoded. https://flowviz.app/app#m= is written exactly as shown, then the encoded source, then %0A.

If you can run code

If you can run code, generate the link instead of encoding by hand. Both snippets print the same link as the recipe above.

Python

from urllib.parse import quote
source = """flowchart TD
    A[Start] --> B[End]"""
link = "https://flowviz.app/app#m=" + quote(source + "\n", safe="")
print(f"[Open in FlowViz]({link})")

JavaScript

const source = `flowchart TD
    A[Start] --> B[End]`;
const encoded = encodeURIComponent(source + "\n")
  .replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase());
const link = "https://flowviz.app/app#m=" + encoded;
console.log(`[Open in FlowViz](${link})`);

The Share button in the FlowViz editor makes a shorter, compressed link. Don't try to write compressed links (#z= or ?d=) by hand. Use #m=.

Other formats FlowViz opens

  • https://flowviz.app/app#z=…: Compressed (DEFLATE with a checksum), generated by FlowViz. Opens as-is; do not write one by hand.
  • https://flowviz.app/app#pako:…: A Mermaid Live Editor link. Replace https://mermaid.live/edit with https://flowviz.app/app and keep everything from #pako: on.
  • https://flowviz.app/app?d=…: Older FlowViz links (lz-string compressed). They still open, but new links should use #m=.
  • https://flowviz.app/s/<id>: Short links the user creates in the editor. These are the one case where a diagram is stored on the server; stored copies are deleted after 3 months.

For developers

FlowViz reads a diagram from the URL fragment (after #), which browsers never send to a server, so opening a link your code, extension or bot built makes no request that carries the diagram. Links open at https://flowviz.app/app.

Link formats

  • #m=<percent-encoded source>: Plain. Build it with encodeURIComponent in any language, following the Recipe. The decoder is lenient about the mistakes people and models make: raw spaces and newlines, + for space, a Markdown code fence around the whole diagram, and punctuation a chat app glues onto the end.
  • #z=<data>: Compressed, written by the editor's Share button: base64url (no padding) of the raw DEFLATE (level 9) of the UTF-8 source, followed by the 4-byte big-endian CRC32 of the compressed bytes. Usually much shorter than the same diagram as #m=. A link that fails the checksum is refused rather than opened as a slightly different diagram.

Mermaid Live import

  • A Mermaid Live Editor link opens in FlowViz: replace https://mermaid.live/edit with https://flowviz.app/app and keep everything from #pako: on. The older #base64: form works the same way.
  • Pasting a Mermaid Live URL into the FlowViz code editor offers to import it.
  • FlowViz takes the diagram code, and the Mermaid Live theme when FlowViz has the same one. Other Mermaid Live settings are ignored.

Query parameters

  • ref: Where the link came from, for example ref=chatgpt or ref=my-extension. A short slug: lowercase letters, digits and - _ ., up to 40 characters. Anything else is ignored. It is counted in FlowViz's analytics together with whether the link opened.
  • theme: The FlowViz theme to open in, by slug: default, neutral, forest, base, ocean, sunset, high-contrast, monochrome, dark, purple. Case doesn't matter, and old theme names still work (for example dark-protocol, ocean-breeze). An unknown value is ignored and the visitor keeps their own theme. Slugs never change. See every theme at https://flowviz.app/themes.
  • view: edit or preview: which pane a phone shows first. Desktop always shows both.

Query parameters go before the #, for example https://flowviz.app/app?ref=my-extension#m=.... They take effect only when the link carries a diagram. Unlike the fragment, the query is sent to the server, so never put diagram text in it.

JavaScript helper

function flowvizLink(source, ref) {
  const encoded = encodeURIComponent(source + "\n")
    .replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase());
  const query = ref ? "?ref=" + encodeURIComponent(ref) : "";
  return "https://flowviz.app/app" + query + "#m=" + encoded;
}

console.log(flowvizLink("sequenceDiagram\n    Alice->>Bob: Hi", "my-extension"));

Privacy

The diagram travels in the URL fragment (the part after #), which browsers never send to a server. FlowViz opens it entirely in the browser.