Download any Substack publication as a Kindle-ready EPUB. Supports free and paywalled posts, embedded images, a table of contents, and a cover image. Comes with both a command-line interface and a web UI.
Features
- Downloads all posts from any Substack (custom domains supported)
- Converts images to grayscale JPEG sized for Kindle Paperwhite
- Embeds images directly in the EPUB — no internet connection needed on device
- Handles paywalled posts for publications you subscribe to
- Sort by newest, oldest, or most popular
- Optional post limit
- Web UI with real-time download progress and one-click EPUB save
- Docker support for zero-dependency hosting
Table of Contents
Requirements
- Python 3.9+
- pip
Installation
git clone https://github.com/kevinlong206/substack2epub.git
cd substack2epub
pip install -r requirements.txtCommand-Line Usage
Basic download
Downloads all free posts from a Substack and saves them as an EPUB in the current directory.
python3 substack2epub.py https://example.substack.com
Custom domains work too:
python3 substack2epub.py https://www.honest-broker.com
Paywalled posts
To include posts behind the paywall, provide your Substack session cookie. This uses your credentials, so only posts from publications you are actively subscribed to will be downloaded. See Getting Your Session ID below.
Interactive login (recommended — session is cached):
python3 substack2epub.py https://example.substack.com --login
This triggers Substack's magic-link email flow:
- Enter your Substack email address when prompted
- Check your inbox for an email from Substack with a login link
- Copy the full URL from that link and paste it back into the terminal
The session is saved to ~/.config/substack_epub/session.json so you only need to authenticate once. Subsequent runs will reuse the cached session automatically.
Paste the cookie directly:
python3 substack2epub.py https://example.substack.com --session-id YOUR_SID
Clear a saved session:
python3 substack2epub.py --logout
Options
| Flag | Description | Default |
|---|---|---|
--output FILE |
Output EPUB filename | <Publication Name>.epub |
--limit N |
Maximum number of posts to download | all |
--sort new |
Newest posts first | ✓ default |
--sort old |
Oldest posts first | |
--sort popular |
Most-liked posts first | |
--session-id SID |
Substack session cookie for paywalled content | |
--login |
Authenticate via magic-link email flow | |
--logout |
Clear cached session and exit |
Examples:
# Download the 20 most popular posts python3 substack2epub.py https://example.substack.com --sort popular --limit 20 # Save with a custom filename python3 substack2epub.py https://example.substack.com --output my_book.epub # Authenticated download, oldest-first python3 substack2epub.py https://example.substack.com --login --sort old
Web UI
The web UI provides a simple browser interface for downloading EPUBs with real-time progress streaming.
Running the web UI
Then open http://localhost:5000.
Screenshots
Using the web UI
Enter any Substack URL and click Download EPUB. A download panel opens with the following options:
| Option | Description |
|---|---|
| Sort order | Newest first, oldest first, or most popular |
| Limit posts | Download only the first N posts |
| Session ID | Your substack.sid cookie to include paywalled posts (subscriptions only) |
Paywalled posts in the web UI
To download paywalled posts from publications you subscribe to, paste your substack.sid cookie into the Session ID field. You can do this manually (see Getting Your Session ID), or click Auto-detect to have the app read the cookie directly from your local browser (Chrome, Firefox, or Safari). Auto-detect only works when running the web UI locally on the same machine as your browser — it will not work in Docker.
Click Start Download. Progress streams in real time. When complete, a Save EPUB button appears — click it to save the file to your computer.
Note: The web UI is intended for local use. Do not expose it to the internet — your session cookie is sensitive and should never be entered into a third-party hosted service.
Docker
Build the image:
docker build -t substack2epub .Run it:
docker run -p 5000:5000 substack2epub
Then open http://localhost:5000.
Generated EPUBs are written to /tmp inside the container and are available for download through the browser during the session. To persist them to your host machine:
docker run -p 5000:5000 -v /tmp/epubs:/tmp substack2epub
Getting Your Session ID
Your session ID is the substack.sid cookie set when you log in to Substack. It grants access to any publication you subscribe to.
- Log in to substack.com in your browser
- Open DevTools (
F12orCmd+Option+I) - Go to Application → Cookies →
https://substack.com - Find the cookie named
substack.sidand copy its value
Keep this value private. It authenticates you to Substack the same way your browser session does. Don't share it or commit it to version control.

