Skip to content

Send a notebook to someone who doesn't run Jupyter

The notebook is done and someone needs to see it — a PM, a client, or a colleague who has never opened Jupyter. Handing over the .ipynb gives them a setup task. Export the HTML and ship it instead: they get your results, not an environment to install.

Drop your Jupyter report here — get a live link

free, no account needed.

Shipping…

The artifact dead-end

Every standard route forces your reader to battle Jupyter's tooling before they see the data: GitHub rendering requires repo access, nbviewer demands a public host first, and asking people to 'just install it and run the cells' is a favour nobody owes you.

Flattening it down is just as grim — screenshots butcher wide tables, and PDF exports mangle everything else. An nbconvert HTML export is already the finished report, outputs baked right in. It just needs a URL.

Two lines to a live link

Build your output like you already do, then hand the folder to the action:

Turn the notebook into HTML

jupyter nbconvert --to html --execute report.ipynb

.github/workflows/ci.yml

- uses: bitgate/ship-page-action@v1
  if: always()
  with:
    path: report.html

Or with plain curl — no account needed

curl -fsS -X POST https://ship.page/deploy \
  -H "Content-Type: text/html" \
  --data-binary @report.html | jq -r .url

path: report.html deploys exactly what the tool wrote — no detection to configure. The link goes in the job summary — add comment: true and it lands on the pull request too.

What you get

  • The export is a true snapshot: code, outputs, tables, and charts frozen mid-run — your reader needs a browser, not a kernel
  • --execute runs every cell top-to-bottom on a fresh kernel at export, ensuring the HTML can't ship stale outputs left behind three sessions ago
  • Images embed as base64 in one self-contained HTML file — a single upload, nothing else to ship
  • Access control lives in the link: an unguessable slug, noindex headers, zero public index
  • Anonymous drops need no account; an sp_ key and a name lock in one stable URL for a recurring report

Downloadable example

A real export, end to end

A synthetic notebook — just a pandas table and a matplotlib chart — executed and exported with the exact command above. Open it in a new tab, or download it and re-upload it yourself.

Questions

Do the interactive parts still work?

Anything that runs on pure front-end JavaScript keeps working; anything expecting a round-trip to a Python kernel does not — there is no kernel behind a static file. Widgets freeze in their last rendered state. You're sharing a snapshot of results, not a live execution environment.

How do I make sure the outputs are fresh?

Export with --execute: nbconvert executes the notebook top to bottom against a fresh kernel before emitting the HTML. Without it, you export whatever stale state you last saved to disk — including that stack trace you forgot was sitting in cell nine.

What does the recipient need installed?

A browser. The export is a single self-contained HTML file (CSS inlined, images embedded) served from its own dedicated subdomain. No Jupyter, no Python, no account.

Can I keep one URL for a report that regenerates?

Yes: deploy with an sp_ API key and a name, and every subsequent run overwrites that exact URL in place. In CI, passing the action a name: input handles updates on schedule — the link your team bookmarked never goes stale.

How is this different from nbviewer?

nbviewer fetches and re-renders your .ipynb from a public URL, on its own schedule and with its own styling opinions. This serves your exported HTML directly: the exact styling you shipped, private by obscurity, online as long as you keep it.

Related recipes

Try it on your next run

Anonymous deploys need no account and no key — paste the step, get a link. When you want stable URLs that redeploy in place, an API key and a name are all it takes.

Need to share the report with someone outside GitHub? How to share a GitHub Actions artifact without a login.