CLI tool to download posts from Substack blogs
Project description
Substack Downloader
Simple CLI tool to download one or all the posts from a Substack blog.
Installation
Using uvx (recommended, no install needed)
uvx sbstck-dl download --url https://example.substack.com
Using pip / pipx
pip install sbstck-dl
# or
pipx install sbstck-dl
Downloading the binary
Check in the releases page for the latest version of the binary for your platform. We provide binaries for Linux, MacOS and Windows.
Using Go
go install github.com/alexferrari88/sbstck-dl
Your Go bin directory must be in your PATH. You can add it by adding the following line to your .bashrc or .zshrc:
export PATH=$PATH:$(go env GOPATH)/bin
Usage
Usage:
sbstck-dl [command]
Available Commands:
download Download individual posts or the entire public archive
help Help about any command
list List the posts of a Substack
version Print the version number of sbstck-dl
Flags:
--after string Download posts published after this date (format: YYYY-MM-DD)
--before string Download posts published before this date (format: YYYY-MM-DD)
--cookie_name cookieName Either substack.sid or connect.sid, based on your cookie (required for private newsletters)
--cookie_val string The substack.sid/connect.sid cookie value (required for private newsletters)
-h, --help help for sbstck-dl
-x, --proxy string Specify the proxy url
-r, --rate int Specify the rate of requests per second (default 2)
-v, --verbose Enable verbose output
Use "sbstck-dl [command] --help" for more information about a command.
Downloading posts
You can provide the url of a single post or the main url of the Substack you want to download.
By providing the main URL of a Substack, the downloader will download all the posts of the archive.
When downloading the full archive, if the downloader is interrupted, at the next execution it will resume the download of the remaining posts.
Usage:
sbstck-dl download [flags]
Flags:
--add-source-url Add the original post URL at the end of the downloaded file
--create-archive Create an archive index page linking all downloaded posts
--download-files Download file attachments locally and update content to reference local files
--download-images Download images locally and update content to reference local files
-d, --dry-run Enable dry run
--file-extensions string Comma-separated list of file extensions to download (e.g., 'pdf,docx,txt'). If empty, downloads all file types
--files-dir string Directory name for downloaded file attachments (default "files")
-f, --format string Specify the output format (options: "html", "md", "txt" (default "html")
-h, --help help for download
--image-quality string Image quality to download (options: "high", "medium", "low") (default "high")
--images-dir string Directory name for downloaded images (default "images")
-o, --output string Specify the download directory (default ".")
-u, --url string Specify the Substack url
Global Flags:
--after string Download posts published after this date (format: YYYY-MM-DD)
--before string Download posts published before this date (format: YYYY-MM-DD)
--cookie_name cookieName Either substack.sid or connect.sid, based on your cookie (required for private newsletters)
--cookie_val string The substack.sid/connect.sid cookie value (required for private newsletters)
-x, --proxy string Specify the proxy url
-r, --rate int Specify the rate of requests per second (default 2)
-v, --verbose Enable verbose output
Adding Source URL
If you use the --add-source-url flag, each downloaded file will have the following line appended to its content:
original content: POST_URL
Where POST_URL is the canonical URL of the downloaded post. For HTML format, this will be wrapped in a small paragraph with a link.
Downloading Images
Use the --download-images flag to download all images from Substack posts locally. This ensures posts remain accessible even if images are deleted from Substack's CDN.
Features:
- Downloads images at optimal quality (high/medium/low)
- Creates organized directory structure:
{output}/images/{post-slug}/ - Updates HTML/Markdown content to reference local image paths
- Handles all Substack image formats and CDN patterns
- Graceful error handling for individual image failures
Examples:
# Download posts with high-quality images (default)
sbstck-dl download --url https://example.substack.com --download-images
# Download with medium quality images
sbstck-dl download --url https://example.substack.com --download-images --image-quality medium
# Download with custom images directory name
sbstck-dl download --url https://example.substack.com --download-images --images-dir assets
# Download single post with images in markdown format
sbstck-dl download --url https://example.substack.com/p/post-title --download-images --format md
Image Quality Options:
high: 1456px width (best quality, larger files)medium: 848px width (balanced quality/size)low: 424px width (smaller files, mobile-optimized)
Directory Structure:
output/
├── 20231201_120000_post-title.html
└── images/
└── post-title/
├── image1_1456x819.jpeg
├── image2_848x636.png
└── image3_1272x720.webp
Downloading File Attachments
Use the --download-files flag to download all file attachments from Substack posts locally. This ensures posts remain accessible even if files are removed from Substack's servers.
Features:
- Downloads file attachments using CSS selector
.file-embed-button.wide - Optional file extension filtering (e.g., only PDFs and Word documents)
- Creates organized directory structure:
{output}/files/{post-slug}/ - Updates HTML content to reference local file paths
- Handles filename sanitization and collision avoidance
- Graceful error handling for individual file download failures
Examples:
# Download posts with all file attachments
sbstck-dl download --url https://example.substack.com --download-files
# Download only specific file types
sbstck-dl download --url https://example.substack.com --download-files --file-extensions "pdf,docx,txt"
# Download with custom files directory name
sbstck-dl download --url https://example.substack.com --download-files --files-dir attachments
# Download single post with both images and file attachments
sbstck-dl download --url https://example.substack.com/p/post-title --download-images --download-files --format md
File Extension Filtering:
- Specify extensions without dots:
pdf,docx,txt - Case insensitive matching
- If no extensions specified, downloads all file types
Directory Structure with Files:
output/
├── 20231201_120000_post-title.html
├── images/
│ └── post-title/
│ ├── image1_1456x819.jpeg
│ └── image2_848x636.png
└── files/
└── post-title/
├── document.pdf
├── spreadsheet.xlsx
└── presentation.pptx
Creating Archive Index Pages
Use the --create-archive flag to generate an organized index page that links all downloaded posts with their metadata. This creates a beautiful overview of your downloaded content, making it easy to browse and access your Substack archive.
Features:
- Creates
index.{format}file matching your selected output format (HTML/Markdown/Text) - Links to all downloaded posts using relative file paths
- Displays post titles, publication dates, and download timestamps
- Shows post descriptions/subtitles and cover images when available
- Automatically sorts posts by publication date (newest first)
- Works with both single post and bulk downloads
Examples:
# Download entire archive and create index page
sbstck-dl download --url https://example.substack.com --create-archive
# Create archive index in Markdown format
sbstck-dl download --url https://example.substack.com --create-archive --format md
# Build archive over time with single posts
sbstck-dl download --url https://example.substack.com/p/post-title --create-archive
# Complete download with all features
sbstck-dl download --url https://example.substack.com --download-images --download-files --create-archive
# Custom directory structure with archive
sbstck-dl download --url https://example.substack.com --create-archive --images-dir assets --files-dir attachments
Archive Content Per Post:
- Title: Clickable link to the downloaded post file
- Publication Date: When the post was originally published on Substack
- Download Date: When you downloaded the post locally
- Description: Post subtitle or description (when available)
- Cover Image: Featured image from the post (when available)
Archive Format Examples:
HTML Format: Styled webpage with images, organized post cards, and hover effects Markdown Format: Clean markdown with headers, links, and image references Text Format: Plain text listing with all metadata for maximum compatibility
Directory Structure with Archive:
output/
├── index.html # Archive index page
├── 20231201_120000_post-title.html
├── 20231115_090000_another-post.html
├── images/
│ ├── post-title/
│ │ └── image1_1456x819.jpeg
│ └── another-post/
│ └── image2_848x636.png
└── files/
├── post-title/
│ └── document.pdf
└── another-post/
└── spreadsheet.xlsx
Listing posts
Usage:
sbstck-dl list [flags]
Flags:
-h, --help help for list
-u, --url string Specify the Substack url
Global Flags:
--after string Download posts published after this date (format: YYYY-MM-DD)
--before string Download posts published before this date (format: YYYY-MM-DD)
--cookie_name cookieName Either substack.sid or connect.sid, based on your cookie (required for private newsletters)
--cookie_val string The substack.sid/connect.sid cookie value (required for private newsletters)
-x, --proxy string Specify the proxy url
-r, --rate int Specify the rate of requests per second (default 2)
-v, --verbose Enable verbose output
Private Newsletters
In order to download the full text of private newsletters you need to provide the cookie name and value of your session.
The cookie name is either substack.sid or connect.sid, based on your cookie.
To get the cookie value you can use the developer tools of your browser.
Once you have the cookie name and value, you can pass them to the downloader using the --cookie_name and --cookie_val flags.
Example
sbstck-dl download --url https://example.substack.com --cookie_name substack.sid --cookie_val COOKIE_VALUE
Thanks
TODO
- Improve retry logic
- Implement loading from config file
- Add support for downloading images
- Add support for downloading file attachments
- Add archive index page functionality
- Add tests
- Add CI
- Add documentation
- Add support for private newsletters
- Implement filtering by date
- Implement resuming downloads
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sbstck_dl-0.7.0-py3-none-win_arm64.whl.
File metadata
- Download URL: sbstck_dl-0.7.0-py3-none-win_arm64.whl
- Upload date:
- Size: 8.7 MB
- Tags: Python 3, Windows ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da7c2ba587b852410c7c63d468c38287e63f9008223853708849a0080d6b4cfd
|
|
| MD5 |
802c474f661c761ff5b1916a9b54b854
|
|
| BLAKE2b-256 |
47a65066ce94b2aa7e47e6b97a04107a6b6f9bd292db76e0499dd35a4cf8c97c
|
File details
Details for the file sbstck_dl-0.7.0-py3-none-win_amd64.whl.
File metadata
- Download URL: sbstck_dl-0.7.0-py3-none-win_amd64.whl
- Upload date:
- Size: 9.4 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0dba6980d70e1f710a0ed978c63d7fc1dbcd491a9439d00f5fc157c54c022a5
|
|
| MD5 |
ff58c24e1c276121b24c5f80d18c7b0c
|
|
| BLAKE2b-256 |
81f0032b8036e9f66fe16ec4bc6839e95e38bbf17b83140186f1c5f4a61ee10f
|
File details
Details for the file sbstck_dl-0.7.0-py3-none-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: sbstck_dl-0.7.0-py3-none-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 9.1 MB
- Tags: Python 3, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3dcaa57bac82b0b2b64f5ec2dd06ea1f028af30da90a7e5a2ef56829c9f5f284
|
|
| MD5 |
a46fbbaddbcd1014049fa34ca06d00e8
|
|
| BLAKE2b-256 |
eebbd5fdcbf04990fd1468a5ff02f84f36d6ea98c86a815a893833833ea91631
|
File details
Details for the file sbstck_dl-0.7.0-py3-none-musllinux_1_2_aarch64.whl.
File metadata
- Download URL: sbstck_dl-0.7.0-py3-none-musllinux_1_2_aarch64.whl
- Upload date:
- Size: 8.5 MB
- Tags: Python 3, musllinux: musl 1.2+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ecd188e21b8448c2567a0f6d63e31d8b1320fe64eb8f3c4d992b611bcdbd29e0
|
|
| MD5 |
6106598a9d72fb0d7c79dae050e6ed8c
|
|
| BLAKE2b-256 |
a89596b247cb86c6fcd5fe4d2bc86a3df0793f0e608d816136363f6eab98ca53
|
File details
Details for the file sbstck_dl-0.7.0-py3-none-manylinux_2_17_x86_64.whl.
File metadata
- Download URL: sbstck_dl-0.7.0-py3-none-manylinux_2_17_x86_64.whl
- Upload date:
- Size: 9.1 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2304dcd354e35fdc68bc2cea8e57923de9785e1b11c6a4bbf0fd58b0d968cf19
|
|
| MD5 |
f1cff930ed0f30a97f1ddda25592950d
|
|
| BLAKE2b-256 |
2923a59b833c2eb3c9830913c0706bce1bf340645d3d2bfe2260daeb757d5f3d
|
File details
Details for the file sbstck_dl-0.7.0-py3-none-manylinux_2_17_aarch64.whl.
File metadata
- Download URL: sbstck_dl-0.7.0-py3-none-manylinux_2_17_aarch64.whl
- Upload date:
- Size: 8.5 MB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
183e3fed01c19c0fea461d40cc4312ba4f4e19a614d608acfb574bb789d67d19
|
|
| MD5 |
08effc3bed61846364eac3d2969e2c44
|
|
| BLAKE2b-256 |
763f1add31a8df165b03c4f45ff42fc3f5cb521a8dc30504616075250546ea02
|
File details
Details for the file sbstck_dl-0.7.0-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: sbstck_dl-0.7.0-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 8.8 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8d4d4610290f8aca1fe8da8c4dd669f31da3df0519ea7a8685a27aad9489bd9
|
|
| MD5 |
2f814769e3ab690f39f596b0ded9f89b
|
|
| BLAKE2b-256 |
3f433d8d13135b70faf6ff1a5c5e3f683d12ce18a64dc5daaa0914ba268a6d8e
|
File details
Details for the file sbstck_dl-0.7.0-py3-none-macosx_10_9_x86_64.whl.
File metadata
- Download URL: sbstck_dl-0.7.0-py3-none-macosx_10_9_x86_64.whl
- Upload date:
- Size: 9.3 MB
- Tags: Python 3, macOS 10.9+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
95bf1decd9d2745ac36b4773f42bb54da7d08bd10c48ddc70951e5a3c5e30fe5
|
|
| MD5 |
39e3b9ca49366bba4de6e2cdae613f22
|
|
| BLAKE2b-256 |
4505f3d9ce23f3928b3766c55173b627f58afd6e1a8e6f0ffae2e9b097902e4c
|