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.htmlbecomes 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 stepfile://cannot do.- Scripts run inside a sandboxed iframe (
allow-scripts, noallow-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.