Share a D3 visualization

D3 is not a charting library, which is exactly why sharing one is harder than sharing a chart. You did not build a picture of the data — you built a force simulation somebody is supposed to drag, a brushable timeline they filter with, a zoomable treemap that only makes its point at the third level down.

None of that survives a screenshot, and a GIF of you using it is a demonstration, not a tool.

The two ways it breaks in transit

Data loading. The common pattern loads data at runtime:

const data = await d3.csv("sales.csv");

From a file:// origin, the browser blocks that fetch as a cross-origin request. So the page opens, the SVG element exists, and nothing is ever drawn — with the failure only visible in the console. This is the single most common reason a colleague reports "your chart is blank" for a file that works fine on your machine. See why HTML reports go blank for the general shape of it.

Library loading. An http:// CDN script inside an https:// page is blocked as mixed content, silently.

Publish the folder

Drop the whole directory — the HTML, the data files, any local modules — into the app:

  • index.html becomes the report body.
  • sales.csv, your JS modules and any images upload alongside it, with relative references rewritten to the uploaded copies. d3.csv("sales.csv") now resolves, which is the step file:// cannot do.
  • Scripts run inside a sandboxed iframe (allow-scripts, no allow-same-origin), so the simulation runs, the brush brushes, and the transitions animate.

Or PATCH the entry file from a build script:

curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html dist/index.html \
        --arg t "Supply chain — dependency graph" '{title: $t, html: $html}')"

Inline the library for anything durable

<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>

is fine for a draft and a liability for a report attached to a decision. @7 is a moving target, and the CDN is a third party you have no agreement with. For a visualization that has to render the same way next year, bundle D3 into the page — esbuild --bundle --minify over an entry that imports it is the short version.

From Observable

Observable notebooks are the most common source of D3 work and the most awkward to hand over: a viewer needs an account for a private notebook, and a published one lives on somebody else's domain with their branding.

Export instead — Observable's download-as-tarball, or the runtime embed — which gives you a self-contained folder. Publish that folder and the notebook renders at your URL, under your access controls, with a comment thread on it.

What review adds

  • Anchored threads on a cluster or an outlier — see commenting on HTML.
  • Revisions, so a visualization rebuilt against new data keeps one link.
  • Access per report — private, team, domain-gated or named reviewers. See the sharing model.

Limits

  • Entry HTML: 5 MB. Assets: 25 MB per file, 250 MB and 500 files total. The dataset is usually the file to watch — pre-aggregate rather than shipping raw rows the visualization immediately bins anyway.
  • 60 requests/minute per token.

Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision history.

Publish a visualization →

Related