← Back to Home

kage — Clone Any Website for Offline Reading Without JavaScript

kage — Clone Any Website for Offline Reading Without JavaScript

You hit "Save As" on a page you want to keep, and six months later you open it to find a blank screen, a spinner that never stops, or a copy that still tries to phone home to an analytics server that no longer exists. The page was never really yours — it was a thin client for someone else's JavaScript.

kage (影, "shadow") takes the other road. It drives a real headless Chrome browser, lets the page finish rendering, snapshots the DOM a human would have seen, then rips every script out of it. What lands on disk looks like the live site and runs no code. No tracking, no network calls, no surprises.

Created by Tam Nguyen Duc and written in Go, kage has gathered over 2,700 GitHub stars since its release in June 2026. It's the tool you reach for when you want to archive a site you love, read documentation on a plane, or freeze a piece of the web before it changes forever.

Why It's Trending

  • The web is falling apart — 90% of modern sites require JavaScript to render anything. "Save As" saves a loader shell, not the content. kage snaps your browser's finished view.
  • Zero-JavaScript mirrors — every script tag, event handler, and javascript: URL is stripped. The output is pure HTML + CSS + images that opens straight off disk.
  • Open standard archives (ZIM) — pack a mirror into a single .zim file readable by Kiwix and any ZIM-compatible reader. You're not locked into kage.
  • Self-contained binaries — pack a mirror into a single executable that is the site. Send it to someone who needs nothing installed.
  • Docker-ready — official container with bundled Chromium, no host setup required.
  • Polite crawler — respects robots.txt, reads sitemap.xml, uses breadth-first crawl with configurable concurrency.

Prerequisites

  • Go 1.22+ (to build from source, or use a prebuilt binary)
  • Chrome or Chromium on the host (kage finds it automatically; use --chrome to point elsewhere)
  • OR Docker — the container image bundles Chromium

Installation

Prebuilt Binary (macOS, Linux, Windows)

Grab the latest release from GitHub releases. Archives, .deb, .rpm, and .apk packages are available.

Go Install

go install github.com/tamnd/kage/cmd/kage@latest

Homebrew (macOS)

brew install --cask tamnd/tap/kage

Docker

docker pull ghcr.io/tamnd/kage

Linux Package Managers

Debian / Ubuntu:

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

Fedora / RHEL:

sudo dnf config-manager --add-repo https://tamnd.github.io/linux-repo/dnf/tamnd.repo
sudo dnf install kage

Quick Start

Clone a website and serve it offline — two commands, ten seconds:

# 1. Clone Paul Graham's essays into ~/data/kage/paulgraham.com/
kage clone paulgraham.com

# 2. Serve it on http://127.0.0.1:8800
kage serve ~/data/kage/paulgraham.com

Open http://127.0.0.1:8800 in your browser. Every essay, every image, every stylesheet — frozen on your disk and running with zero network.

Clone Options

kage gives you fine-grained control over the crawl:

Flag Default Purpose
--max-pages / -p 0 (unlimited) Stop after N pages
--max-depth / -d 0 (unlimited) How many links deep to follow
--scope-prefix Only crawl paths under this prefix
--subdomains false Include subdomains of the seed host
--scroll false Auto-scroll to trigger lazy-loaded images
--workers 4 Concurrent page renders
--refresh false Re-render existing pages in place
--exclude Path prefixes to skip (repeatable)

Examples:

# Quick snapshot — 50 pages, 2 links deep
kage clone paulgraham.com --max-pages 50 --max-depth 2

# Whole section of a documentation site
kage clone go.dev --scope-prefix /doc

# Large site with subdomains, lazy-loaded content
kage clone example.com --subdomains --scroll --workers 8

# Catch up: re-render pages that have changed
kage clone paulgraham.com --refresh

Packing for Sharing

A mirror is a folder — great for browsing, lousy for moving around. Use kage pack to collapse it into a single artifact:

ZIM archive (recommended for portability):

kage pack paulgraham.com
# Creates paulgraham.com.zim
kage open paulgraham.com.zim

ZIM is an open standard used by Kiwix, Wikipedia offline, and Project Gutenberg. Your archive works with any ZIM reader today and years from now.

Self-contained binary:

kage pack paulgraham.com --format binary -o paulgraham
./paulgraham

A single executable that serves the site. Whoever you send it to needs nothing installed — not kage, not a ZIM reader, nothing.

Desktop app (double-click ready):

# macOS
kage pack paulgraham.com --app
open paulgraham.app

# Linux (AppImage)
kage pack paulgraham.com --app --base kage-linux-amd64

Architecture

kage Architecture

kage's pipeline is divided into five stages:

  1. Crawl — The seed URL feeds into a breadth-first crawl frontier that respects robots.txt, reads sitemap.xml, and stays on the seed host. Each discovered URL is normalized and deduplicated — the same page reached via HTTP vs HTTPS or with/without trailing slash is fetched exactly once.

  2. Render — A pool of headless Chrome tabs (default: 4 workers) renders each page and waits for it to settle. The --scroll flag triggers lazy-loaded images. kage takes a snapshot of the DOM a human would have seen — not the raw HTML but the post-JavaScript rendered state.

  3. Sanitize — Every <script> tag, inline event handler (onclick, onload, etc.), and javascript: URL is stripped from the snapshot. The result is pure HTML that can never make a network call or execute code.

  4. Localize — CSS, images, and fonts are downloaded via a separate HTTP asset pool. All URLs in the HTML are rewritten to local paths. The output structure mirrors the original site: paulgraham.com/index.html, paulgraham.com/greatwork.html, paulgraham.com/_kage/ for assets.

  5. Pack — The mirror on disk can be collapsed into a ZIM archive (zstd-compressed, open standard), a self-contained binary (kage + archive appended), or a double-click desktop app (.app on macOS, AppImage on Linux).

Docker Usage

Skip installing Chrome entirely. The official container bundles Chromium:

docker run --rm -v "$PWD/out:/out" ghcr.io/tamnd/kage clone paulgraham.com

The mirror lands in ./out/paulgraham.com/ on your host. Serve it:

docker run --rm -v "$PWD/out:/out" -p 8800:8800 ghcr.io/tamnd/kage serve /out/paulgraham.com

kage serve and kage open

  • kage serve <mirror-dir> — runs a tiny static file server on port 8800. Links and assets resolve exactly as they would on the live host.
  • kage open <file.zim> — serves a ZIM archive through the same HTTP interface.
  • Native window — build with -tags webview and kage opens in a native OS window (WKWebView on macOS, WebView2 on Windows, WebKitGTK on Linux) instead of a browser tab.

Use Cases

  • Flight mode reading — clone a blog or documentation site before a trip. Read offline at 35,000 feet.
  • Documentation archiving — freeze a version of your project's docs before a major redesign.
  • Research preservation — capture articles, papers, and references before they disappear behind paywalls or get taken down.
  • Historical snapshots — keep a personal archive of sites you care about, viewable exactly as they were.
  • Knowledge sharing — pack a ZIM or binary and share it with colleagues who need offline access.

Resources

← Retour à l'Accueil

kage — Clonez n'importe quel site web pour une lecture hors ligne sans JavaScript

kage — Clonez n'importe quel site web pour une lecture hors ligne sans JavaScript

Vous cliquez sur « Enregistrer sous » pour une page que vous voulez garder, et six mois plus tard vous l'ouvrez pour trouver un écran blanc, un spinner qui ne s'arrête jamais, ou une copie qui essaie encore de contacter un serveur d'analyse qui n'existe plus. La page n'a jamais vraiment été à vous — ce n'était qu'un client léger pour le JavaScript de quelqu'un d'autre.

kage (影, « ombre ») emprunte un autre chemin. Il pilote un vrai navigateur Chrome headless, laisse la page terminer son rendu, capture le DOM qu'un humain aurait vu, puis arrache tous les scripts. Ce qui atterrit sur le disque ressemble au site en direct mais n'exécute aucun code. Pas de pistage, pas d'appels réseau, pas de surprises.

Créé par Tam Nguyen Duc et écrit en Go, kage a déjà rassemblé plus de 2 700 étoiles GitHub depuis sa sortie en juin 2026. C'est l'outil que vous utilisez pour archiver un site que vous aimez, lire de la documentation dans un avion, ou figer un morceau du web avant qu'il ne change pour toujours.

Pourquoi Ça Cartonne

  • Le web se dégrade — 90 % des sites modernes nécessitent JavaScript pour afficher quoi que ce soit. « Enregistrer sous » sauvegarde une coquille vide, pas le contenu. kage capture la vue finale de votre navigateur.
  • Miroirs zéro JavaScript — chaque balise <script>, gestionnaire d'événement et URL javascript: est supprimée. Le résultat est du HTML pur + CSS + images qui s'ouvre directement depuis le disque.
  • Archives ouvertes (ZIM) — condensez un miroir en un seul fichier .zim lisible par Kiwix et tout lecteur compatible ZIM. Vous n'êtes pas verrouillé dans kage.
  • Binaires autonomes — condensez un miroir en un exécutable unique qui est le site. Envoyez-le à quelqu'un qui n'a rien besoin d'installer.
  • Prêt pour Docker — conteneur officiel avec Chromium intégré, aucune configuration hôte requise.
  • Robot poli — respecte robots.txt, lit sitemap.xml, utilise un parcours en largeur avec une concurrence configurable.

Prérequis

  • Go 1.22+ (pour compiler depuis les sources, ou utilisez un binaire précompilé)
  • Chrome ou Chromium sur la machine hôte (kage le trouve automatiquement ; utilisez --chrome pour pointer ailleurs)
  • OU Docker — l'image conteneur inclut Chromium

Installation

Binaire Précompilé (macOS, Linux, Windows)

Téléchargez la dernière version depuis GitHub releases. Les archives, paquets .deb, .rpm et .apk sont disponibles.

Go Install

go install github.com/tamnd/kage/cmd/kage@latest

Homebrew (macOS)

brew install --cask tamnd/tap/kage

Docker

docker pull ghcr.io/tamnd/kage

Gestionnaires de Paquets Linux

Debian / Ubuntu :

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

Fedora / RHEL :

sudo dnf config-manager --add-repo https://tamnd.github.io/linux-repo/dnf/tamnd.repo
sudo dnf install kage

Démarrage Rapide

Clonez un site web et servez-le hors ligne — deux commandes, dix secondes :

# 1. Clonez les essais de Paul Graham dans ~/data/kage/paulgraham.com/
kage clone paulgraham.com

# 2. Servez-les sur http://127.0.0.1:8800
kage serve ~/data/kage/paulgraham.com

Ouvrez http://127.0.0.1:8800 dans votre navigateur. Chaque essai, chaque image, chaque feuille de style — figé sur votre disque et fonctionnant sans réseau.

Options de Clone

kage vous offre un contrôle fin sur le parcours :

Option Défaut Utilité
--max-pages / -p 0 (illimité) Arrêter après N pages
--max-depth / -d 0 (illimité) Profondeur des liens à suivre
--scope-prefix Parcourir seulement les chemins sous ce préfixe
--subdomains false Inclure les sous-domaines du site hôte
--scroll false Défilement automatique pour les images lazyload
--workers 4 Rendu concurrent de pages
--refresh false Re-rendre les pages existantes sur place
--exclude Préfixes de chemins à ignorer (répétable)

Exemples :

# Aperçu rapide — 50 pages, 2 niveaux de profondeur
kage clone paulgraham.com --max-pages 50 --max-depth 2

# Section entière d'un site de documentation
kage clone go.dev --scope-prefix /doc

# Grand site avec sous-domaines, contenu lazyload
kage clone example.com --subdomains --scroll --workers 8

# Mise à jour : re-rendre les pages modifiées
kage clone paulgraham.com --refresh

Conditionnement pour le Partage

Un miroir est un dossier — idéal pour naviguer, peu pratique pour le transport. Utilisez kage pack pour le réduire en un artefact unique :

Archive ZIM (recommandée pour la portabilité) :

kage pack paulgraham.com
# Crée paulgraham.com.zim
kage open paulgraham.com.zim

ZIM est un standard ouvert utilisé par Kiwix, Wikipédia hors ligne et le Projet Gutenberg. Votre archive fonctionne avec n'importe quel lecteur ZIM aujourd'hui et dans des années.

Binaire autonome :

kage pack paulgraham.com --format binary -o paulgraham
./paulgraham

Un exécutable unique qui sert le site. La personne à qui vous l'envoyez n'a rien besoin d'installer — ni kage, ni lecteur ZIM, rien.

Application desktop (prête à double-cliquer) :

# macOS
kage pack paulgraham.com --app
open paulgraham.app

# Linux (AppImage)
kage pack paulgraham.com --app --base kage-linux-amd64

Architecture

Architecture de kage

Le pipeline de kage est divisé en cinq étapes :

  1. Parcours — L'URL source alimente une file d'attente de parcours en largeur qui respecte robots.txt, lit sitemap.xml et reste sur le site hôte. Chaque URL découverte est normalisée et dédoublonnée — la même page atteinte via HTTP vs HTTPS ou avec/sans slash final est récupérée une seule fois.

  2. Rendu — Un pool d'onglets Chrome headless (4 workers par défaut) rend chaque page et attend qu'elle se stabilise. L'option --scroll déclenche le chargement des images lazyload. kage capture le DOM qu'un humain aurait vu — pas le HTML brut mais l'état rendu après JavaScript.

  3. Nettoyage — Chaque balise <script>, gestionnaire d'événement inline (onclick, onload, etc.) et URL javascript: est supprimée. Le résultat est du HTML pur qui ne peut jamais faire d'appel réseau ou exécuter de code.

  4. Localisation — Les CSS, images et polices sont téléchargées via un pool HTTP d'actifs séparé. Toutes les URLs dans le HTML sont réécrites en chemins locaux. La structure de sortie reflète le site d'origine : paulgraham.com/index.html, paulgraham.com/greatwork.html, paulgraham.com/_kage/ pour les actifs.

  5. Conditionnement — Le miroir sur disque peut être réduit en une archive ZIM (compressée zstd, standard ouvert), un binaire autonome (kage + archive annexée), ou une application desktop à double-clic (.app sur macOS, AppImage sur Linux).

Utilisation avec Docker

Évitez d'installer Chrome. Le conteneur officiel inclut Chromium :

docker run --rm -v "$PWD/out:/out" ghcr.io/tamnd/kage clone paulgraham.com

Le miroir atterrit dans ./out/paulgraham.com/ sur votre machine. Servez-le :

docker run --rm -v "$PWD/out:/out" -p 8800:8800 ghcr.io/tamnd/kage serve /out/paulgraham.com

kage serve et kage open

  • kage serve <dossier-miroir> — lance un petit serveur de fichiers statiques sur le port 8800. Les liens et actifs se résolvent exactement comme sur le site en direct.
  • kage open <fichier.zim> — sert une archive ZIM via la même interface HTTP.
  • Fenêtre native — compilé avec -tags webview, kage s'ouvre dans une fenêtre OS native (WKWebView sur macOS, WebView2 sur Windows, WebKitGTK sur Linux) au lieu d'un onglet navigateur.

Cas d'Utilisation

  • Lecture en mode avion — clonez un blog ou un site de documentation avant un voyage. Lisez hors ligne à 10 000 mètres d'altitude.
  • Archivage de documentation — figez une version de la documentation de votre projet avant une refonte majeure.
  • Préservation de recherche — capturez des articles, papiers et références avant qu'ils ne disparaissent derrière des paywalls ou ne soient supprimés.
  • Instantanés historiques — conservez une archive personnelle des sites qui vous tiennent à cœur, visibles exactement comme ils étaient.
  • Partage de connaissances — créez un ZIM ou un binaire et partagez-le avec des collègues qui ont besoin d'un accès hors ligne.

Ressources