Sankey Chart Generator Back to editor

Build an importable Sankey diagram

This guide gives AI agents and automation tools the exact JSON contract used by Sankey Chart Generator.

Your data stays local. Import JSON reads a file on the user's device. There is no upload API, account, database, or server-side diagram processing.

Copy-ready agent prompt

Paste this into an AI agent, then add the diagram topic, values, and any presentation requirements.

Create a Sankey Chart Generator diagram as JSON that validates against
https://sankey-chart-generator.vercel.app/diagram.schema.json.

Attach the diagram as a downloadable diagram file (.json). The file must contain
only the JSON object, without Markdown fences or commentary. Include title, unit,
nodeColors, layout.labelSize, layout.positions, and flows.

If the user has not supplied data, ask a follow-up question before creating the
file. Ask what the diagram should visualise and where the data can be found or
how the user can provide it (for example by pasting, uploading, or describing it).
Do not invent values or sources.

Use unique stable flow IDs, positive numeric values, six-digit hexadecimal
colours, and an acyclic directed diagram. Infer nodes from flow source and target
names. Keep every intermediate node's incoming and outgoing totals balanced
unless an imbalance is intentional.

Put the complete, language-ready subtitle in unit because the editor renders it
verbatim. Use layout.positions = {} unless manual normalized positions are
required. Default to layout.showValues = true and layout.showPercentages = false
unless the requested chart needs percentages; layout.percentageBasis must be
parent or first-main.

For externally sourced real-world values, include provenance with a specific
source label, a direct HTTP(S) URL, and the YYYY-MM-DD date the values represent
in asOf. Omit provenance for fictional or illustrative data. The provenance
object is machine-readable metadata and is not displayed on the chart.

Omit branding unless visible attribution or a supplied logo is needed. If branding
is included, provide both fields: use branding.source for visible attribution (or
an empty string) and set branding.logo = null unless the user supplies a supported
PNG, JPEG, or WebP base64 data URL and normalized x, y, width, and height. Do not
fetch, invent, or embed a logo on your own; it can be added in the editor after
import.

Why keep provenance? It makes real-world values traceable without forcing a citation onto the rendered chart. Use branding.source separately when readers should see attribution.

Why keep logos in JSON? It preserves logos when a diagram is exported and re-imported. For new files, adding a logo through the editor is simpler and avoids asking an agent to handle large image data.

Quick start

  1. Create one JSON object that follows diagram.schema.json.
  2. Use unique, stable IDs and positive numeric values for every flow.
  3. Keep the diagram acyclic. For every intermediate node, make incoming and outgoing totals equal unless the imbalance is intentional.
  4. Save the object as a .json file, then choose Import JSON in the editor.

Importable example

A minimal balanced diagram with illustrative values, so provenance is intentionally omitted.

Open JSON Schema
{
  "title": "Customer conversion",
  "unit": "Monthly customer conversion in users",
  "nodeColors": {
    "Visitors": "#2f6fbe",
    "Customers": "#397f50"
  },
  "nodeLabelColors": {
    "Customers": "#1f5d38"
  },
  "layout": {
    "labelSize": 18,
    "titleColor": "#0a284f",
    "subtitleColor": "#69778a",
    "numberFormat": {
      "thousandsSeparator": "comma",
      "decimalSeparator": "dot",
      "decimalPlaces": 0
    },
    "showValues": true,
    "showPercentages": false,
    "percentageBasis": "parent",
    "percentageDecimalPlaces": 1,
    "positions": {}
  },
  "flows": [
    {
      "id": "visitors-to-trials",
      "source": "Visitors",
      "target": "Trials",
      "value": 1200,
      "color": "#7196b8"
    },
    {
      "id": "trials-to-customers",
      "source": "Trials",
      "target": "Customers",
      "value": 1200,
      "color": "#67a879"
    }
  ]
}

Field reference

FieldRequiredMeaning
titleYesDiagram heading. Empty text is allowed.
unitYesComplete subtitle rendered verbatim, such as Figures in USD millions. The editor adds no language-specific prefix.
provenanceNoTraceability metadata for externally sourced real-world values: a specific source label, direct HTTP(S) URL, and the YYYY-MM-DD date the values represent. Omit for fictional or illustrative data. This is not rendered on the chart.
nodeColorsYesMap from exact node name to a six-digit hexadecimal colour.
nodeLabelColorsNoMap from exact node name to a six-digit hexadecimal label colour. Unlisted nodes use the default label colour.
branding.sourceNoOptional attribution text rendered at the chart’s bottom-left edge. Unlike provenance, this is visible to readers.
branding.logoNoA PNG, JPEG, or WebP base64 data URL with normalized x, y, width, and height. Keep null unless preserving a logo supplied by the user; the editor can add one after import.
layout.labelSizeYesOne shared node-label size from 12 through 28.
layout.titleColorNoSix-digit hexadecimal title colour.
layout.subtitleColorNoSix-digit hexadecimal subtitle colour.
layout.numberFormatNoFormatting settings: thousandsSeparator is comma, dot, or space; decimalSeparator is comma or dot; decimalPlaces is 0–6.
layout.showValuesNoShow or hide numeric node values. Defaults to true.
layout.showPercentagesNoShow or hide derived node percentages. Defaults to false.
layout.percentageBasisNoparent compares with the immediate upstream node; first-main compares with the earliest aggregation or branching node.
layout.percentageDecimalPlacesNoPercentage precision from 0–6, independent of value precision.
layout.positionsYesOptional node-name map to normalized x/y values from 0 through 1. Use {} for automatic layout.
flowsYesArray of directed source-to-target quantities. Nodes are inferred from endpoint names.
flow.idYesA non-empty ID unique within this diagram.
flow.sourceYesExact name of the node where the flow starts.
flow.targetYesExact name of the different node where the flow ends.
flow.valueYesA finite number greater than zero.
flow.colorYesA six-digit hexadecimal colour used for this flow.

Validation and balance

Blocking validation

A file is rejected when an endpoint is blank, a value is not positive, a flow uses the same source and target, IDs repeat, or the directed diagram contains a cycle. JSON Schema verifies document shape; cycle detection happens during import.

Non-blocking balance warnings

An intermediate node receives flows and distributes flows. When those totals differ, the editor shows a prominent warning with the incoming total, outgoing total, and difference. The diagram still renders, saves, and exports because an imbalance may be intentional.

Positions and names

Position keys must exactly match node names. The editor constrains horizontal movement so nodes cannot cross their upstream or downstream layers. Reset layout removes all saved positions.

Troubleshooting

  • Schema-valid but import fails: check for a directed cycle, repeated flow ID, or identical source and target.
  • Diagram imports with a warning: compare incoming and outgoing totals for the named intermediate node.
  • Labels are crowded: shorten names, lower layout.labelSize, or leave positions empty and reset the automatic layout.