Skip to content

IPYNB to HTML Converter

Turn a .ipynb file into a single web page anyone can open in a browser, with no Jupyter and no internet. Charts, tables and maths are inside the file, and it carries no scripts. Nothing is uploaded.

v2026.10.16

Open a Jupyter notebook

No Jupyter, no install, no upload.

Sample

bike-rides.ipynb

Python 3 (ipykernel)Python 3.12.4nbformat 4.512 cells · 154 words · 1 picture

One .html file with the styles, pictures and maths inside and no scripts. It opens offline and follows the reader’s light or dark setting.

Bike rides and rain: a short walkthrough

A week of made-up numbers from a small town's bike-share scheme. It shows what a notebook can hold: Markdown, code, a table, a chart, maths, a warning and, at the end, an error.

In [1]
import pandas as pd
import matplotlib.pyplot as plt
In [2]
rides = pd.DataFrame({
    "day": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
    "trips": [412, 438, 395, 451, 288, 230],
    "rain_mm": [0.0, 1.2, 4.5, 0.0, 9.8, 14.1],
}).set_index("day")
rides
Out [2]
trips rain_mm
day
Mon 412 0.0
Tue 438 1.2
Wed 395 4.5
Thu 451 0.0
Fri 288 9.8
Sat 230 14.1

How busy was the week?

The mean number of trips per day is

xˉ=1n∑i=1nxi\bar{x} = \frac{1}{n}\sum_{i=1}^{n} x_i

where nn is the number of days and xix_i is the number of trips on day ii.

In [3]
mean = rides["trips"].mean()
print(f"Mean trips per day: {mean:.1f}")
print(f"Busiest day: {rides['trips'].idxmax()}")
Mean trips per day: 369.0
Busiest day: Thu
In [4]
import warnings

if rides["rain_mm"].max() > 10:
    warnings.warn("Saturday had over 10 mm of rain; the gauge reads high in storms.")
/tmp/ipykernel_4120/2715331896.py:4: UserWarning: Saturday had over 10 mm of rain; the gauge reads high in storms.
  warnings.warn("Saturday had over 10 mm of rain; the gauge reads high in storms.")

Rain and riding

Fewer people rode on wet days. Pearson’s correlation coefficient measures how closely two columns move together, from −1 to 1:

r=∑i(xi−xˉ)(yi−yˉ)∑i(xi−xˉ)2 ∑i(yi−yˉ)2r = \frac{\sum_i (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum_i (x_i - \bar{x})^2}\,\sqrt{\sum_i (y_i - \bar{y})^2}}

In [5]
fig, ax = plt.subplots(figsize=(6.4, 3.6))
ax.bar(rides.index, rides["trips"], color="#4878d0")
ax.set_ylabel("Trips")
ax.set_title("Bike-share trips per day")
plt.show()
Image output of cell 8
In [6]
round(rides["trips"].corr(rides["rain_mm"]), 3)
Out [6]
-0.979

A day that isn’t there

There is no Sunday in the data, so asking for it raises a KeyError. This is what a traceback looks like:

In [7]
rides.loc["Sun"]

KeyError: 'Sun'

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[7], line 1
----> 1 rides.loc["Sun"]

File ~/.venv/lib/python3.12/site-packages/pandas/core/indexes/base.py:3812, in Index.get_loc(self, key)
   3810     return self._engine.get_loc(casted_key)
   3811 except KeyError as err:
-> 3812     raise KeyError(key) from err

KeyError: 'Sun'

What next

  • Load a week of rides
  • Chart them
  • Add the weekend’s weather from the town’s own gauge

Made-up data, made for this example. Any resemblance to a real town is a coincidence.

Your notebook is read on this device and never uploaded. Check it yourself

How this works: Method, 6 sources, Checked against 1 worked example,

How this works

Method

The .ipynb file is read in the browser as the nbformat JSON it is: every cell, its last outputs and its attachments. Markdown is drawn with GitHub Flavored Markdown and maths with KaTeX, code is coloured by the notebook’s language, and each output shows its richest format, as JupyterLab chooses. All HTML from the notebook is sanitised first and nothing from other sites is loaded. PDF comes from the browser’s print engine; HTML, script and Markdown files are written in the page.

How it’s tested

One worked example for this page is checked by automated tests before every release: given the inputs, the tool must show the expected answer.

Privacy

On your device. Nothing you enter or open leaves this browser. About privacy labels

Changes

  • First published: open a .ipynb file with its outputs, maths and colours, and save it as PDF, HTML, a script or Markdown.

Every change on What’s new

How we make toolsReport a mistake

One file that opens anywhere

An HTML copy is the easiest way to share a notebook with someone who doesn’t use Jupyter. They double-click it and it opens in their browser, with the charts, tables and formatted text exactly as you saw them, and they can read it on a phone.

The file this page makes needs nothing from the internet. Its styles are written inside it, its pictures are embedded as data, and its equations are MathML, the maths markup browsers draw on their own, so there is no stylesheet or font to download. jupyter nbconvert --to html, by contrast, points to MathJax on a CDN by default to draw equations, so maths in its files needs a connection the first time it opens.

It also carries no JavaScript. Notebooks can contain HTML written by anyone, so every piece is cleaned of scripts and event handlers first, and the file declares a content security policy that forbids scripts outright. That matters if you are passing on a notebook someone else wrote: the copy can’t run code on whoever opens it.

Interactive outputs, such as widgets or a Plotly chart, are programs rather than pictures, so they appear as a short note, or as the still image the notebook saved with them. Pictures linked from other sites keep their address, so they load when the reader is online.

Good to know

How to convert a Jupyter notebook to HTML3 steps, all on your device
  1. Open the notebook. Drop the .ipynb file on the card or choose it from your device.
  2. Choose code or outputs only. Keep the code for a technical reader, or choose Outputs only to send results to someone who doesn’t need it.
  3. Save the HTML file. Press Save HTML. You get one .html file that opens in any browser, offline, and follows the reader’s light or dark setting.

Frequently Asked Questions

Will the HTML file work offline?

Yes. Styles, pictures and equations are all inside the one file, so it opens with no connection. Only pictures the notebook linked from other websites need the internet.

Is it safe to send someone the HTML?

The file has no scripts: HTML from the notebook is cleaned of them, and a content security policy in the file blocks any script from running. It is a document, not a program.

Can I put it on a website?

Yes. It is a normal HTML page with its CSS inside, so you can upload it to any static host, attach it to an email or add it to a course page.

Does it look the same as in Jupyter?

Close to it: code is coloured, outputs keep their In and Out numbers, and pandas tables are styled. It follows the reader’s light or dark mode.

“Jupyter” is a trademark of Project Jupyter, used here only to say which files this viewer opens. Binary Decimal is not affiliated with or endorsed by Project Jupyter.