# 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.

Source: https://flowviz.app/docs/share-links · Markdown: https://flowviz.app/docs/share-links.md · Last updated: 2026-09-24

For AI assistants: follow the Recipe, check the Mermaid rules, and copy the pattern of the Examples (flowchart, sequence and ER diagrams included). The Mermaid code must be URI-encoded.

For developers: "For developers" at the end covers both link formats, Mermaid Live import, the `?ref=` parameter and a JavaScript helper.

## 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:

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

  Right:

  ```mermaid
  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:

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

  Right:

  ```mermaid
  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:

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

  Right:

  ```mermaid
  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:

  ```mermaid
  erDiagram
      POST ||--{ POST_TAG : has
  ```

  Right:

  ```mermaid
  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:

  ```mermaid
  erDiagram
      TAG {
          int id PK
          string name
          unique
      }
  ```

  Right:

  ```mermaid
  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:

  ```mermaid
  classDiagram
      abstract class Shape {
          +area() double
      }
  ```

  Right:

  ```mermaid
  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:

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

  Right:

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

## Characters that break links

| Character | Encoded |
|---|---|
| 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 below is the Mermaid source above it, encoded with the recipe. Every one is tested to open the exact diagram.

### Flowchart

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

[Open in FlowViz](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

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

[Open in FlowViz](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`.

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

[Open in FlowViz](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

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

[Open in FlowViz](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

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

[Open in FlowViz](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

```mermaid
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
```

[Open in FlowViz](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

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

[Open in FlowViz](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`.

```mermaid
mindmap
  root((Trip))
    Travel
      Flights
    Stay
      Hotel
```

[Open in FlowViz](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

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

[Open in FlowViz](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

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

[Open in FlowViz](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.

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

[Open in FlowViz](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.

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

[Open in FlowViz](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.

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

[Open in FlowViz](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

```javascript
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.
