Share an nbconvert HTML export

jupyter nbconvert --to html is the most reliable thing in the notebook ecosystem. It takes an .ipynb and gives you one file that renders in any browser, with the plots where you left them.

Then the file sits in your working directory, and the actual question — how does someone else see this — starts over from scratch. Email it and it's an attachment nobody can comment on. Push it to a gist and the scripts don't run. Commit it and the diff is a wall of base64.

Publish it

jupyter nbconvert --to html --embed-images analysis.ipynb

curl -X POST https://commareports.com/api/v1/reports \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html analysis.html \
        '{title: "Churn analysis — cohort 2026-Q2", html: $html}')"

Or drag analysis.html into the app.

--embed-images is the flag that matters. Without it, matplotlib output is written to a sibling analysis_files/ directory and the published page has broken image slots — the classic broken-CSS-and-images failure of a self-contained-looking export that isn't.

Add --no-input when the reader is a stakeholder rather than a colleague. The distinction is real: the same notebook is a method document for one audience and a set of conclusions for the other.

What the URL changes

  • Comments land on the cell. "Is this filtering out the trial accounts?" pinned to the cell it's about, not paraphrased in Slack three days later. See commenting on HTML.
  • Re-runs are revisions. PATCH the same id when the data refreshes. Same URL, new numbers, old numbers still there to compare.
  • Interactive outputs survive. Plotly, Bokeh, Altair and ipywidgets static output all render — scripts run inside a sandboxed iframe (allow-scripts, no allow-same-origin).
  • Private by default. A notebook usually holds real customer numbers. Access is per report — team, email-domain gate, named reviewers, or a password-protected link. See the sharing model.

On a schedule

The notebook that answers a recurring question should not need you to run it. A routine executes it on a cron and PATCHes the same report, so the weekly number is current at a URL people already have — see scheduled HTML reports.

Limits

  • HTML body: 5 MB. --embed-images inlines every figure as base64, so a notebook with fifty plots gets large fast. Downsample the figures, or drop --embed-images and upload the _files/ directory alongside as assets.
  • Scripts run, sandboxed: allow-scripts, no allow-same-origin.
  • 60 requests/minute per token.

Try it

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

Create your first report →

Related