Archive any website as a ZIP of full-page screenshots — every page discovered, captured exactly as your browser serves it, stamped with URL + capture time, and packed with a JSON manifest, a browsable gallery, and optional PDF book and contact-sheet poster.
Built for designers archiving site designs, QA teams documenting regressions, and anyone who needs a verifiable, point-in-time record of a website — including pages behind a login.
- Download
site-snapshotter-vX.Y.Z.zipfrom the Releases page and unzip it. - In Chrome:
chrome://extensions→ enable Developer mode → Load unpacked → select the unzipped folder.
git clone https://github.com/mantisdotdev/site-snapshotter.git
cd site-snapshotter
npm install
npm run buildThen load dist/ as above (chrome://extensions → Developer mode → Load unpacked).
- Click the toolbar icon, enter a site URL (it prefills from the active tab).
- Pick a preset (Design archive / Compliance / QA audit) or set options individually:
- Scope — whole site (sitemap + crawl) or home page + nav bar pages only; optionally review/prune the discovered list before capturing.
- Variants — tablet and mobile viewports, dark + light color-scheme shots, retina (2×).
- Extras — MHTML page archives, a merged PDF site book (cover + contents), a contact-sheet poster PNG.
- Report data — per-page issues (console errors, failed requests, redirects) and SEO metadata (h1, description, og:image, canonical).
- Run-to-run diffing — each run pixel-compares against the previous run of the same site (baseline kept in IndexedDB): cards get
no change/Δ 3.2%/new pagechips, the summary counts changes, andmanifest.jsonrecords per-page diff status.
- Set the page limit (default 50), settle wait, and page-prep toggles.
- Start capture opens a dashboard tab — a contact sheet that fills in live. After the run, any frame has a retake button.
- When the run finishes (or you cancel), Download ZIP.
The ZIP contains (extras only when enabled):
shots/001-index.png # full-page PNGs, provenance banner on top
shots/001-index--mobile-dark.png # variant shots, when enabled
pages-mhtml/001-index.mhtml # MHTML archives
manifest.json # per-page URL, title, status, shots, issues, SEO data
index.html # standalone dark gallery of the whole run
poster.png # contact-sheet poster
site-book.pdf # merged PDF book
Everything stays on your machine. Captures are written to a ZIP you save locally; run history and diff baselines live in your browser's local storage. There is no server, no analytics, no telemetry, no network upload of any kind — the only outbound requests are the page fetches needed to crawl the site you asked for.
The extension requests broad permissions because of what it does; none is used for anything else:
| Permission | Why it's needed |
|---|---|
debugger |
Drives a background tab over the DevTools Protocol to take pixel-perfect full-page screenshots in one shot (no stitching seams). This is why Chrome shows an "is debugging this browser" bar during a run. |
<all_urls> (host access) |
You can point it at any site; the crawl fetches pages and sitemaps from the target origin only. |
downloads |
Saves the ZIP via Chrome's download manager (always with a Save-As prompt). |
storage, unlimitedStorage |
Remembers your settings and keeps screenshot baselines for run-to-run diffing. |
Because captures run in your browser session, logged-in pages are captured as you see them — ZIPs can contain private content; treat them as sensitive.
- Discovery — whole-site scope reads
robots.txt/sitemap.xml(incl. one level of sitemap index), falling back to a same-host breadth-first link crawl. Nav scope loads the home page in the worker tab and collects links from its rendered<nav>/<header>/role="navigation"landmarks (so JS-rendered menus work). Trailing-slash and#fragmentvariants are deduped; query strings are kept as distinct pages. - Capture — a pinned background worker tab is driven over the Chrome DevTools Protocol (
chrome.debugger): navigate → wait for load + settle → freeze CSS animations → dismiss cookie banners → auto-scroll for lazy-load → hide chat widgets → one-shotPage.captureScreenshotwithcaptureBeyondViewport(no stitching). - Variants — viewports via
Emulation.setDeviceMetricsOverride, dark/light via emulatedprefers-color-scheme, retina via capture scale. Each page loads once; variants are shot back-to-back. - Provenance — each PNG gets a banner with the URL and local capture time; the same data lands in
manifest.json. Run summaries (no images) are kept inchrome.storage.local; the latest run's base shots stay in IndexedDB as the diffing baseline for the next run.
- Chrome shows an "is debugging this browser" bar during a run — that's the price of pixel-perfect one-shot captures. It disappears when the run ends.
- Page height is capped at 16,000 CSS px; width at 3,000 (taller pages are marked
truncated). - Closing the dashboard tab stops the run.
npm run typecheck # tsc --noEmit
npm run build # esbuild → dist/
npm run watch # rebuild on change (reload the extension in Chrome after)Full gate: npm run typecheck && npm run build && node test/e2e.mjs. The end-to-end suite drives
the built extension in a real Chromium via Playwright and byte-verifies the ZIP output (see its
header for setup). Icons regenerate with tools/gen-icons.mjs.
Open items live in BACKLOG.md; architectural decisions in docs/DECISIONS.md.

