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.html becomes 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, no allow-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, interact sliders. 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.

Publish a book →

Related