Share a Jupyter Book
Jupyter Book turns a folder of notebooks and markdown into a real
publication — chapters, cross-references, citations, executed outputs.
jupyter-book build . produces _build/html/, and then the docs hand you
a deployment problem: set up ghp-import, or a Pages action, or Netlify.
For a book that should be public and permanent, do that. For the ones that shouldn't — a draft under review, an internal methods document, a deliverable for a client — the deployment step is out of proportion to the need, and it is where most books quietly stop.
Build it
jupyter-book build .
# → _build/html/index.html
_build/html/
├── index.html
├── chapters/…/analysis.html # one page per notebook or md file
├── _static/ # css, js, the search index
├── _images/ # figures from executed cells
└── searchindex.js
Drop the folder in
Drag _build/html/ (or a zip of it) into
Comma:
index.htmlbecomes the report body — the page carrying the comment layer.- Chapter pages,
_static/,_images/and the search index upload alongside it, with relative references rewritten to the uploaded copies. - Scripts run inside a sandboxed iframe (
allow-scripts, noallow-same-origin), so search, the sidebar, the collapsible code cells and the copy-button all work.
One URL, no Pages workflow, no bucket.
What survives and what doesn't
Worth being precise, because "interactive notebook" covers two very different things:
- Survives: matplotlib and seaborn figures, Plotly / Bokeh / Altair output embedded at build time, rendered dataframes, MyST directives, citations and cross-references. These are all baked into the HTML.
- Doesn't: anything needing a live Python kernel — ipywidgets bound to
callbacks,
interactsliders. That's a property of static HTML, not of where you host it; the same book on Pages behaves identically.
If a chapter needs a kernel, link out to Binder or Colab from it, which is what Jupyter Book's launch buttons already do.
From CI, for a per-branch draft
jupyter-book build .
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 _build/html/index.html \
--arg title "Methods — $(git rev-parse --abbrev-ref HEAD)" \
'{title: $title, html: $html}')"
The API is JSON-only, so the chapter pages and figures go up through
POST /api/v1/reports/$REPORT_ID/assets as base64 — one call per file,
worth scripting once. See the API reference and
publishing from CI.
PATCHing a saved id keeps one URL with a revision per build, so a book
that regenerates when the data updates always has one current address.
Review on the prose, not in email
A book is written to be argued with, and the arguments are specific: this assumption, that figure, this cohort definition. In the normal flow they arrive as an email listing "section 3.2, paragraph 4."
Published, they land on the paragraph. Select it, leave a thread, and it stays anchored across rebuilds — so the objection and the sentence it concerns stay together. See commenting on HTML.
Who can see it
Per report: private, your team, any signed-in user with the link, or public. A draft gets a link-only URL for the reviewers; an internal methods document gets a team report. Domain-gating, password gates and expiring links are Enterprise. See sharing & access control.
Limits
- Entry HTML: 5 MB. Assets: 25 MB per file, 250 MB and 500 files total. A long book with many executed figures can approach the file count — publish the section under review rather than the whole book.
- Scripts run, sandboxed — no same-origin access.
- 60 requests/minute per token.
Try it
Comma is free — unlimited reports, unlimited commenters, unlimited revision history.