nbsanity - Share Notebooks as Polished Web Pages in Seconds

Transform your GitHub Jupyter notebooks into beautiful, readable web pages with a single URL change. No setup required.
Author

Hamel Husain

Published

December 13, 2024

At fastai, we’ve long believed that Jupyter Notebooks are an excellent medium for technical writing, combining live code, visualizations, and narrative text in a single document. However, sharing notebooks in a way that’s both beautiful and accessible has always been a challenge. While GitHub’s notebook viewer is functional, it lacks the polish and features needed for proper technical communication. Today, we’re introducing nbsanity, a service that transforms any public GitHub notebook into a polished web page with just a URL change.

The Challenge

While GitHub’s rendering is functional, it suffers from several limitations: the rendering can be sluggish and occasionally fails completely, there’s no way to collapse or hide code cells, and the presentation can’t be customized. One particularly frustrating issue is the lack of horizontal scrolling for code cells, and overall, the reading experience isn’t optimized for consumption.

Nbviewer solves some of these issues, but doesn’t allow you to customize the presentation. We’ve previously addressed some of these challenges with tools like fastpages and nbdev, but these solutions require setup and maintenance 1. We realized there was a need for something simpler - a solution that would allow instant sharing without any overhead.

I’ve been searching for the perfect low-friction system for technical writing ever since discovering Simon Willison’s elegant TIL (Today I Learned) approach. With nbsanity, we finally have it.

What is nbsanity?

nbsanity is a free service that renders any public Jupyter notebook from GitHub or Gists as a polished web page. There’s no setup, no configuration, and no deployment needed.

nbsanity is powered by Quarto, an open-source scientific and technical publishing system. Through our extensive work with various documentation tools, we’ve found Quarto to be the most ergonomic static site generator available for notebooks. It offers seamless integration with both Jupyter and VSCode through dedicated extensions, while providing remarkable flexibility in output formats - including presentations, books, PDFs and websites.

One of Quarto’s most powerful features is its “directives” system - simple cell comments that begin with #| that allow you to customize how your content is rendered. These directives are easy to add and do not clutter your code. Below are examples of Quarto capabilities you get access to with nbsanity:

  • Cell Visibility Control: Hide specific cells with #|include: false while keeping their execution
  • Output Management: Show just results with #|echo: false or raw output with #|output: asis
  • Error Handling: Control error messages with #|error: false and warnings with #|warning: false
  • Content Organization: Create tab panels with {.panel-tabset} and callouts with :::{.callout-note} (this is not a directive, but markdown cell syntax that creates tab panels and callouts.).
  • Layout Control: Apply custom CSS classes and control figure layouts with directives like #| fig-width: and #| layout-ncol:

Documentation concerning these directives can be found in the more resources section.

nbsanity is focused on doing one thing well: rendering public notebooks beautifully. This means it only works with notebooks hosted on GitHub or in Gists. Furthermore, you’ll need to use remote URLs for any images in your notebooks2. These constraints let us deliver a service that’s simple, fast, and completely maintenance-free for users. Think of nbsanity as the “pastebin for notebooks” - it’s the fastest way to go from a GitHub notebook to a polished reading experience.

We added extra love

In addition to Quarto’s rendering process, we’ve added several quality-of-life improvements. All rendered notebooks have a (1) table of contents, (2) link to the original GitHub URL, (3) and wrap text in code cells.

We’ve even made sure that rendered notebooks have fancy social cards, thanks to Simon Willison’s shot-scraper:

These social cards show the actual contents of your notebook and help your posts stand out on social media.

Getting Started

Using nbsanity couldn’t be simpler. You have two options:

Option 1: URL Modification

Replace github.com with nbsanity.com in any GitHub notebook URL. This works for both repositories and gists. For example:

GitHub URL   https://github.com/fastai/lm-hackers/blob/main/lm-hackers.ipynb

nbsanity URL https://nbsanity.com/fastai/lm-hackers/blob/main/lm-hackers.ipynb

For gists, the URL format is slightly different: nbsanity.com/gist/[username]/[gist_id]. See these instructions for more details.

Option 2: Bookmarklet

For even faster conversion, drag this bookmarklet to your bookmarks bar:

nbsanity

Clicking on this bookmarklet while viewing a public GitHub notebook will perform the necessary url substitution for you.

A Demo

To demonstrate Quarto’s capabilities, let’s examine one of my favorite features: code-folding.

Example 1

To collapse a code cell with an expandable summary, I can add the following directive to the top of a code cell:

#| code-fold: true
#| code-summary: "Click to see data preprocessing"

These rendering instructions are used to create this effect, but are not rendered and seen by the reader.

Click to see data preprocessing
import pandas as pd
import numpy as np

# Create sample data
np.random.seed(42)
data = pd.DataFrame({
    'id': range(1000),
    'value': np.random.normal(0, 1, 1000),
    'category': np.random.choice(['A', 'B', 'C'], 1000)
})

# Preprocessing steps
data['value_normalized'] = (data['value'] - data['value'].mean()) / data['value'].std()
data['value_binned'] = pd.qcut(data['value'], q=5, labels=['Q1', 'Q2', 'Q3', 'Q4', 'Q5'])

Example 2

To specify that you want readers to have the option to collapse code, we can use the same code-fold directive with a different option:

#| code-fold: show
Code
import matplotlib.pyplot as plt

plt.figure(figsize=(8, 4))
plt.plot(np.random.randn(100).cumsum())
plt.title('Random Walk')
plt.show()

Important Notes

While nbsanity makes notebook sharing effortless, there are a few key things to keep in mind to use it well. First, nbsanity is a rendering service only - it displays your notebooks but does not execute them, even if you have Quarto directives that say otherwise. This avoids potential security issues.

nbsanity also has a a caching system that preserves the history of your notebook renders. Each time you render a notebook, you receive a unique link corresponding to that specific version. If you later update your notebook and render it again, you’ll get a new link. All previous versions remain accessible through their original links. Any new rendering capabilities we introduce will only apply to new renders, meaning your existing shared notebooks will maintain their original appearance.

Next Steps with nbsanity

We built nbsanity because we believe that reducing friction in sharing knowledge is important. We’ve been refining nbsanity with our community of over 2,000 students in our solveit course, where it’s become an integral part of how students share their work. Their feedback and usage patterns have helped us polish the tool into something we love using ourselves.

The best way to get started is to try it yourself:

  1. Visit nbsanity.com and drag the bookmarklet to your browser’s bookmark bar
  2. Navigate to any public Jupyter notebook on GitHub
  3. Click the bookmarklet to view the notebook with beautiful Quarto rendering

Whether you’re writing “Today I Learned” posts, sharing technical tutorials, or enhancing your project’s documentation, we hope this tool makes your technical writing journey a little bit easier. The project is open source and available on GitHub—we welcome your feedback and contributions!3

P.S. If you share your notebook using nbsanity on social media, please tag me—I’d love to see your work! You can find me on twitter and linkedin.

More resources

Here are links to Quarto docs I find helpful when authoring notebooks:

  1. cell output: hide, show, and filter cell output and input.
  2. code-display: configure how code is displayed, including line-numbers, folding of cells, hiding of cells, etc.
  3. figures: configure how figures are shown
  4. tables: configure how tables are shown
  5. metadata: configure the title, subtitle, date, author and more.
  6. numbering: toggle section numbering.

Footnotes

  1. JupyterBook is another project that allows you to customize the presentation of notebooks. Like fastpages, nbdev and other static site generators, these projects require a non-trivial amount of setup and maintenance.↩︎

  2. The reason for requiring remote urls is that we do not want to be rate limited by the GitHub API in fetching related files.↩︎

  3. We need to keep the service minimal, so please expect that we will be discerning about feature requests and PRs.↩︎