Ever Run Into These Problems?
You bookmark a great article, come back months later — blank page, infinite loading spinner, or the whole thing freezes because some long-dead analytics server can't be reached. That page was never really yours. It was just a thin client for someone else's JavaScript.
Another scenario: you need to read a documentation site offline — on a plane, in the field, or in some server room. Or maybe you want to permanently archive a website before it disappears one day.
That's exactly what kage (Japanese for "shadow", pronounced /ka-ge/) was built to solve.
What Is kage?
kage is an open-source command-line tool written in Go. It renders pages with headless Chrome, waits for everything to load, captures a DOM snapshot, then removes all JavaScript and downloads CSS, images, fonts, and other static assets locally. What you get is a collection of .html files you can open directly from disk — no network needed, no scripts executed.
- ⭐ GitHub Stars: 2600+ (created June 2026, growing fast)
- 🏷️ Language: Go
- 📜 License: MIT
- 🧑💻 Author: tamnd
kage vs. Traditional "Save As"
| Feature | Browser "Save As" | wget / curl | kage |
|---|---|---|---|
| JavaScript rendering | ❌ | ❌ | ✅ Full headless Chrome rendering |
| Auto JS stripping | ❌ | ❌ | ✅ Completely removes all scripts |
| SPA/dynamic content | ❌ | ❌ | ✅ Works with Vue/React/Angular pages |
| Full-site cloning | ❌ | ⚠️ Limited | ✅ Follows links automatically, breadth-first crawl |
| Package as single file | ❌ | ❌ | ✅ ZIM / self-contained executable |
| Offline ready | ⚠️ Often broken | ⚠️ Often broken | ✅ Perfect offline experience |
How It Works Under the Hood
Visit URL → headless Chrome renders → Wait for page to stabilize → Capture final DOM → Remove all <script> tags → Download CSS/images/fonts → Save locally → Follow links
kage doesn't just download raw HTML source. It renders the page like a real browser would, making sure what gets saved is exactly what you see with your own eyes.
Installing kage
kage supports multiple installation methods across Linux, macOS, and Windows.
Method 1: Via Go
If you have Go installed (1.21+ recommended):
go install github.com/tamnd/kage/cmd/kage@latest
Method 2: Via Homebrew (macOS)
brew install --cask tamnd/tap/kage
Method 3: Via Scoop (Windows)
scoop bucket add tamnd https://github.com/tamnd/scoop-bucket
scoop install kage
Method 4: Via apt (Ubuntu/Debian)
# Add the repo key and source
curl -fsSL https://tamnd.github.io/linux-repo/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/tamnd.gpg
echo "deb [signed-by=/usr/share/keyrings/tamnd.gpg] https://tamnd.github.io/linux-repo/apt stable main" | sudo tee /etc/apt/sources.list.d/tamnd.list
sudo apt update && sudo apt install kage
Method 5: Via dnf (Fedora/RHEL)
sudo dnf config-manager --add-repo https://tamnd.github.io/linux-repo/dnf/tamnd.repo
sudo dnf install kage
Method 6: Via Docker (No Chrome Install Needed)
The Docker image comes with Chromium built in:
docker run --rm -v "$PWD/out:/out" ghcr.io/tamnd/kage clone paulgraham.com
Verify Installation
kage --version
kage completion bash # or zsh / fish — enables tab completion
Note: kage requires Chrome or Chromium. Unless you're using Docker, you'll need Chrome/Chromium installed on your host. kage auto-detects system installations, or you can specify the path with
--chromeor theKAGE_CHROMEenvironment variable.
Quick Start: Clone a Website in 3 Minutes
Let's clone Paul Graham's blog as an example:
# 1. Clone the entire site to $HOME/data/kage/paulgraham.com/
kage clone paulgraham.com
# 2. Preview locally
kage serve $HOME/data/kage/paulgraham.com
# Open http://127.0.0.1:8800 in your browser
That's it! All articles, images, and stylesheets are frozen on your disk — zero network dependency.
Limiting the Scope
If you just want a quick test run, limit the clone depth:
# Only clone the first 50 pages, follow links up to 2 levels deep
kage clone paulgraham.com --max-pages 50 --max-depth 2
# Only clone a specific subdirectory
kage clone go.dev --scope-prefix /doc
# Skip certain paths (exclude ads or irrelevant pages)
kage clone example.com --exclude /ads --exclude /track
Useful Options Cheat Sheet
| Option | Default | Description |
|---|---|---|
-o, --out |
$HOME/data/kage |
Output root directory |
-p, --max-pages |
0 (unlimited) |
Maximum pages to clone |
-d, --max-depth |
0 (unlimited) |
Link-following depth |
--scope-prefix |
None | Only clone paths starting with this prefix |
--subdomains |
false |
Include subdomains |
--scroll |
false |
Auto-scroll pages (triggers lazy loading) |
--workers |
4 |
Number of concurrent page renders |
--no-robots |
false |
Ignore robots.txt |
--refresh |
false |
Incremental update of existing clone |
Advanced Features
1. Auto-Scroll for Lazy Loading
Many modern sites use lazy loading for images — they won't load unless you scroll. kage handles this:
kage clone example.com --scroll
This makes kage scroll each page all the way to the bottom, ensuring all lazy-loaded images, iframes, and other content get fully rendered and saved.
2. Incremental Updates (--refresh)
Your cloned blog got new posts last month? No need to start over:
kage clone paulgraham.com --refresh
--refresh re-renders existing pages and grabs new content. kage's cloning is idempotent: the same page — whether accessed via http or https — is only saved once.
3. Graceful Interruption & Resume
Hit Ctrl+C mid-clone? No problem — kage saves your progress automatically:
# Press Ctrl+C to interrupt; next run picks up where it left off
kage clone paulgraham.com
4. Include Subdomains
kage clone example.com --subdomains
This also clones blog.example.com, docs.example.com, and other subdomains.
Packaging: From Folder to Single File
After cloning, you have a folder with thousands of small files. Copying it around is slow. kage can compress the entire mirror into a single file.
Option 1: Package as ZIM File
ZIM is an open offline format used by the Kiwix project, designed for long-term archiving:
# Package
kage pack paulgraham.com # Generates paulgraham.com.zim
# Read
kage open paulgraham.com.zim # Preview locally
# Or serve with Kiwix
kiwix-serve paulgraham.com.zim # HTTP server
Why ZIM? It's an open standard. A
.zimfile you create today with kage can still be opened by any Kiwix reader ten years from now. It uses zstd compression — text is highly compressed, images and media are stored as-is.
Option 2: Package as Standalone Executable
This is kage's coolest feature — one executable = an entire website:
# Package as a self-contained binary
kage pack paulgraham.com --format binary -o paulgraham
# Run it directly, zero dependencies
./paulgraham
# Automatically starts an HTTP server — just open it in your browser
Anyone who receives this file doesn't need to install anything: no kage, no browser, no ZIM reader. Just run it and get the full offline website.
The binary is roughly 13 MiB (kage itself) + the website content size.
Cross-Platform Packaging
You can package for Windows from macOS:
# Generate a Windows executable on Mac
kage pack paulgraham.com --format binary \
--base kage-windows-amd64.exe
# Outputs paulgraham.exe
Just download the kage binary for the target platform from the releases page and use it as --base.
Option 3: Double-Click Desktop App
Add the --app flag and kage generates a desktop app with an icon:
# macOS → .app bundle
kage pack paulgraham.com --app
open paulgraham.app
# Linux → AppImage
kage pack paulgraham.com --app --base kage-linux-amd64
# Outputs paulgraham.AppDir / paulgraham.AppImage
Double-click to open — no terminal window, straight into the website.
Real-World Use Cases
Use Case 1: Save a Tech Blog as an Offline Knowledge Base
# Clone all of Paul Graham's essays
kage clone paulgraham.com --scroll -o ~/docs/paulgraham
# Package as ZIM, read on Kindle or phone anytime
kage pack paulgraham.com
# Or package as a single file to share with friends
kage pack paulgraham.com --format binary -o ~/share/paulgraham-essays
Use Case 2: Offline Documentation Sites
# Clone the official Go docs
kage clone go.dev --scope-prefix /doc --max-depth 3
# On a business trip with no Wi-Fi? Just serve locally
kage serve ~/data/kage/go.dev
Use Case 3: Long-Term Archiving
Some websites might shut down or migrate. Use kage to archive regularly:
# Add to cron, auto-update monthly
# 0 2 1 * * kage clone example.com --refresh
Things to Keep in Mind
- robots.txt: kage respects
robots.txtby default. Use--no-robotsif you need to bypass it in dev/test environments. - Chrome dependency: Chrome/Chromium is required on the host (except with Docker).
- Disk space: Large sites can take up several GB after cloning.
- Legality: Respect website copyrights and robots.txt. Don't use it for commercial purposes or to infringe on copyrighted content.
Summary
kage is the most elegant website offline cloning tool available today. It renders pages with headless Chrome, strips all JavaScript, and turns dynamic web pages into static HTML that truly belongs to you. ZIM packaging and self-contained executables make it a perfect solution for long-term archiving and distribution.
- GitHub: tamnd/kage
- Website: kage.tamnd.com
- License: MIT
- Install:
go install github.com/tamnd/kage/cmd/kage@latest
If you often need to read docs offline or want to permanently preserve website content, kage absolutely deserves a spot in your toolbox.