Share a Jupyter notebook as HTML
The analysis is done. The notebook runs top to bottom. Now a PM, a data
lead, and two engineers need to read it and tell you what's wrong with it —
and none of them are going to pip install anything to do it.
The usual answers each solve half the problem. nbviewer renders notebooks
beautifully, but only ones that are already public, and nobody can comment.
GitHub renders .ipynb files in the repo, but statically, behind repo
access, with no way to discuss a specific output. Emailing the exported
.html file works exactly once, and then the feedback scatters across
reply-all.
Comma is the missing step: export the notebook to HTML, publish it, and collect comments anchored to the exact cell or table row being discussed.
The pipeline
1. Export with nbconvert
jupyter nbconvert --to html analysis.ipynb
This snapshots the notebook as it last ran — markdown, code, rendered outputs — into a single HTML file, with figure outputs embedded. Two flags worth knowing:
--no-inputhides the code cells, which turns the export into a stakeholder-facing report instead of a wall of Python.--embed-images(recent nbconvert versions) inlines images your markdown cells reference from disk, so the file is fully self-contained.
2. Publish it to Comma
Three ways in, same result: paste the HTML into the app, drag-drop the
file, or POST it from a terminal. The create endpoint takes JSON with a
required html field plus optional title and description:
jq -Rs '{title: "Retention analysis — July", html: .}' analysis.html |
curl -s -X POST https://commareports.com/api/v1/reports \
-H "Authorization: Bearer $COMMA_API_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @-
The response carries a share_url. Tokens come from
Settings → API tokens, are scoped and revocable, and the HTML limit is
5 MB — notebooks heavy with embedded figures can exceed that, in which case
attach the big images as assets (25 MB per file) instead.
Pass "visibility": "private" at create time to keep the report
invite-only, or set access later from the share dialog — private, your
team, any signed-in user, or anyone with the link. This is the part
nbviewer structurally can't do.
3. Review like a document
Reviewers open the link in a browser — no Jupyter, no environment, no repo access. They highlight a sentence in your markdown commentary or a row in a results table and pin a comment to it, Google-Docs style. Threads, replies, resolve, reopen. Commenting is free and unlimited on every plan; nobody needs a paid seat to say "cell 12's join looks wrong."
4. Re-run, republish, same link
When the comments come back, fix the notebook, export again, and PATCH:
jq -Rs '{html: .}' analysis.html |
curl -s -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
-H "Authorization: Bearer $COMMA_API_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @-
Comma appends a revision under the same URL, keeps the comment threads attached, and can diff any two revisions — so "did the fix change the numbers?" is one click, not an archaeology project.
The honest comparison
| Comma | nbviewer | GitHub rendering | Emailing the .html | |
|---|---|---|---|---|
| Private notebooks | Yes — private / invite / team / public | No — public URLs only | Behind repo access | Whoever has the file |
| Comments | Anchored to cells, text, and table rows | None | On JSON source lines, not outputs | Reply-all |
| Stable link | Yes, survives re-runs | Yes, but render-only | Yes, but static | No link at all |
| Revisions & diffs | Yes, built in | No | Git history of raw JSON | Attachment archaeology |
| Reviewer needs | A browser | A browser | A GitHub account + access | A browser |
| Agent can publish | Yes — REST + MCP under one scoped token | No | Via git, awkwardly | No |
Where the alternatives win: nbviewer is zero-setup for notebooks that are already public — if your notebook lives in a public gist and nobody needs to comment, nbviewer is fine. GitHub rendering is unbeatable for code-review of the notebook's source. Comma is for reviewing the findings.
What renders, honestly
Comma renders your export untouched inside an opaque-origin sandbox — no
reformatting, no restyling. One deliberate exception: the API strips
<script> tags before storage, as defense-in-depth on an endpoint that
accepts arbitrary HTML. For a Jupyter export that means markdown, code
listings, tables, and static figures (matplotlib/seaborn as PNG or SVG)
survive faithfully, while script-driven interactivity — ipywidgets, Plotly
and Bokeh tooltips — renders statically or not at all.
For review that's usually the right trade: a comment can anchor to a rendered chart; it can't anchor to a hover state. Keep the live notebook for exploration and publish the snapshot for review.
From an agent, skip the curl
If Claude Code or Cursor is the thing running the notebook, use Comma's
MCP server instead of shell plumbing. The same comma_sk_… token gates
both surfaces, and the agent gets typed tools: create_report,
update_report, list_comments, reply_to_comment. The end of an
agentic task becomes "run the notebook, export, publish to Comma, return
the share link" — and the start of the next one becomes "read the open
comments and address them." See
Use Comma with Claude Code for the one-line install.
Making it recur
Two ways to keep the report fresh:
- Your scheduler, Comma as destination. A cron job or
CI pipeline runs
jupyter nbconvertand the PATCH call above. Works on every plan. - Comma routines. Hosted scheduling that re-runs a skill and republishes at any cadence on every plan. You pay only for the AI compute — bring your own AWS Bedrock key for free, or draw down prepaid credits. See Routines →.
Try it
Publishing, collaboration, and routines are all free. Export a notebook you've already run and publish it — the difference shows up in the first comment, which lands on the row of the table it's about instead of in a Slack thread describing where to look.
Related
- Use Comma with Quarto — the document-renderer pipeline
- Use Comma with marimo — the reactive-notebook pipeline
- How to share an HTML report — the general pattern
- Publish from CI — automate the export-and-publish step