How to Convert a Jupyter Notebook to PDF (4 Methods That Actually Work in 2026)
You finished the analysis. The charts look good. Now your lecturer, your client, or your hiring manager wants it as a PDF — and jupyter nbconvert --to pdf just threw a wall of red text at you.
This is the single most frustrating export in the Python data stack, and it's frustrating for one specific reason: the default PDF path doesn't use Python at all. It quietly hands your notebook to a LaTeX engine that most people have never installed.
Here are four methods, ordered from "works in 30 seconds" to "produces the nicest output." Pick based on how much you care about the result.
Method 1: Browser print (30 seconds, no installs)
The fastest reliable route. Convert to HTML first, then let your browser make the PDF:
jupyter nbconvert --to html my_notebook.ipynb
This creates my_notebook.html. Open it in Chrome or Edge, press Ctrl+P (Cmd+P on Mac), and choose Save as PDF as the destination.
Before you hit save, open More settings and turn on Background graphics. Without it, your syntax highlighting and any coloured cell backgrounds disappear and the output looks washed out.
No LaTeX. No new packages. Works every time. The trade-off is that page breaks fall wherever they fall, so a code block can get split across two pages.
Method 2: WebPDF (best balance of quality and hassle)
This is the method I'd actually recommend for most people. It renders the notebook in a headless Chromium browser and prints to PDF — so you get proper HTML rendering, working emoji, and no LaTeX anywhere.
pip install "nbconvert[webpdf]"
playwright install chromium
jupyter nbconvert --to webpdf my_notebook.ipynb
The playwright install chromium step downloads the browser engine — around 130 MB, one time only. If you skip it you'll get an error about a missing browser executable.
If you're on an older nbconvert version that used Pyppeteer instead of Playwright, add the download flag:
jupyter nbconvert --to webpdf --allow-chromium-download my_notebook.ipynb
Method 3: The JupyterLab menu (no terminal at all)
In JupyterLab, go to File → Save and Export Notebook As… → PDF. In the older Jupyter Notebook interface it's File → Download as → PDF via LaTeX.
Be aware: this menu item calls the same LaTeX pipeline as Method 4. If you haven't installed a TeX distribution, it will fail with the same error. It's convenient, not different.
Method 4: LaTeX (the real fix for the original error)
If you want the classic typeset look — proper margins, real typography, publication-quality output — you need the LaTeX toolchain. This is what --to pdf was trying to use all along.
You need two things: Pandoc and a TeX distribution with XeLaTeX.
Windows: install MiKTeX and Pandoc. During your first export MiKTeX will prompt to install missing packages on the fly — say yes, and expect it to ask several times.
macOS:
brew install --cask mactex-no-gui
brew install pandoc
Ubuntu / Debian / WSL:
sudo apt update
sudo apt install pandoc texlive-xetex texlive-fonts-recommended texlive-plain-generic
Then run the original command:
jupyter nbconvert --to pdf my_notebook.ipynb
On Windows, close and reopen your terminal after installing — the PATH won't refresh in an already-open window, and you'll get "xelatex not found" even though it's installed.
The four errors you're most likely to hit
"nbconvert failed: xelatex not found on PATH"
No TeX distribution installed, or your terminal is using a stale PATH. Install per Method 4, then restart the terminal. Verify with xelatex --version.
"PDF creating failed, captured latex output:" followed by nothing useful
Almost always a missing LaTeX package or an unsupported character. Get the real error by converting to .tex and compiling it yourself:
jupyter nbconvert --to latex my_notebook.ipynb
xelatex my_notebook.tex
The second command prints the actual failure instead of swallowing it.
Emoji or non-English characters break the build
XeLaTeX can't render glyphs that aren't in its fonts, and emoji in markdown cells are the usual culprit. Strip them, or switch to Method 2 — WebPDF handles Unicode without complaint.
Long lines of code run off the right margin
A genuine limitation of the LaTeX template — it doesn't wrap code. Break long lines in your source cells before exporting, or use Method 1 or 2, which wrap naturally.
Hiding code so only results show
For a client or a non-technical reader, you usually want the charts and conclusions without the code. Use tag-based removal.
In JupyterLab, open the property inspector (the gear icon in the right sidebar), select a cell, and add the tag hide_code under Cell tags. Then export with:
jupyter nbconvert --to webpdf \
--TagRemovePreprocessor.enabled=True \
--TagRemovePreprocessor.remove_input_tags="hide_code" \
my_notebook.ipynb
To strip every code cell and keep only outputs and markdown, there's a built-in shortcut:
jupyter nbconvert --to webpdf --no-input my_notebook.ipynb
That single flag is the one most people are looking for when they ask how to make a notebook "look like a report."
Which method should you use?
- Need it in the next two minutes: Method 1, browser print.
- Sharing with a client or submitting coursework: Method 2, WebPDF with
--no-input. - Academic paper or anything typeset: Method 4, LaTeX.
- You avoid the terminal: Method 3 — but install LaTeX first.
For day-to-day work, Method 2 is the one worth setting up properly. It's a single install, it never fails on Unicode, and the output is close enough to LaTeX quality that nobody asks questions.
Related guides on this blog:
Post a Comment