Skip to content

joeseverino/sitedrift

Repository files navigation

sitedrift

Catch the drift between dev and live. A zero-build, zero-dependency dev tool that frames your local site and production side-by-side on the same route, locked to the same scroll — then overlays them in difference mode so the only things that light up are the pixels that actually changed.

sitedrift comparing a redesigned local product page with production

Same route. Same scroll. Every change visible.


Quick start

No install — run it with npx (needs Node ≥ 18):

npx sitedrift /pricing \
  --dev http://localhost:4321 \
  --live https://example.com \
  --open

That boots the viewer on http://127.0.0.1:4178, opens it at /pricing, and puts your dev build on the left and production on the right. Type any route in the toolbar and both panes follow.

Install it globally if you reach for it often:

npm i -g sitedrift
sitedrift /pricing -d http://localhost:4321 -l https://example.com -o

Bind securely to loopback while using an existing local DNS name and certificate:

sitedrift / --host 127.0.0.1 --hostname compare.homelab \
  --cert /path/to/fullchain.pem --key /path/to/compare.homelab.key

For a project you use repeatedly, add sitedrift.config.json:

{
  "dev": "http://localhost:4321",
  "live": "https://example.com",
  "author": "joe",
  "open": true
}

Configuration precedence is flag > environment > project file > default. The file is discovered from the current directory upward; --config <file> selects one explicitly.

HTTPS

The default (http://127.0.0.1) just works — loopback is a browser "secure context", so you usually need nothing. When you do want HTTPS:

sitedrift --setup-https   # one-time: generate + trust a local cert
sitedrift --https         # serve over HTTPS from then on

--setup-https uses mkcert if it's installed — that gives a locally-trusted cert with zero browser warnings. If mkcert isn't found it falls back to an openssl self-signed cert and prints the one command to trust it on your OS. Already have a cert? Skip all of this and pass --cert <file> --key <file>.

Cloudflare preview deployments

Turn every non-production Cloudflare Pages deployment into a compact sitedrift review URL. The deployment opens its own preview in DEV Solo mode and can switch to Split, Overlay, or Diff against the configured production site.

Install sitedrift, then let init scaffold the integration:

npm install --save-dev sitedrift@latest
npx sitedrift cloudflare init --live https://example.com

init writes the scoped Pages Function (functions/__sitedrift/[[path]].ts), detects your build output directory, and prints the exact build line to paste after your framework build:

{
  "scripts": {
    "build": "astro build && sitedrift cloudflare --dir dist --live https://example.com"
  }
}

(--dir is auto-detected at build time, so the wrapper also works as just sitedrift cloudflare --live https://example.com.) On Cloudflare Pages, the wrapper activates only when CF_PAGES=1 and CF_PAGES_BRANCH is not main. Production builds are left unchanged. Use --production-branch <name> when production is another branch.

Hosted proxies are read-only (GET/HEAD) and fixed to the configured live origin. Frames run the compared site's scripts so interactive previews behave like the deployment; only enable the addon for preview code you trust. Review notes stay in that browser's localStorage; they are not sent to an API, shared with agents, or written to disk. Existing application Functions keep their original routes.

That is two project changes and requires no Cloudflare dashboard settings or bindings. See the complete Cloudflare Pages guide for framework examples, the production guard, security details, and a CI check.

A real Pages deployment

This is the same integration running on jseverino.com. A GitHub branch push created an ordinary Cloudflare Pages preview tied to one repository, branch, commit, and immutable deployment URL:

Cloudflare Pages deployment details for a sitedrift preview

The existing Cloudflare build generated 83 static pages, then the installed sitedrift dependency wrapped those pages before Cloudflare uploaded the assets and scoped Function. There was no separate deployment service or dashboard configuration:

Cloudflare build log showing sitedrift wrapping 83 HTML files

Opening that immutable deployment produces the review UI. DEV is a temporary red-brand branch generated with branding-engine; LIVE is the unchanged navy production site:

Cloudflare preview comparing red DEV with navy LIVE

The source branch was later restored to navy, while the immutable deployment remains a reproducible artifact of the exact reviewed commit.


See the whole review loop

The included example compares a fictional Northstar release candidate against production. It uses realistic release drift: primary CTA, metric values, and a release badge change while the underlying layout stays aligned.

Difference overlay showing only changed pixels
Pixel difference
Overlay both pages and light up only what changed.
Review drawer with notes from a human and an AI agent
Human + AI review channel
Share route-specific findings through the viewer, CLI, or MCP.

sitedrift Solo mode on a narrow mobile viewport
Focused mobile review
Narrow screens default to Solo; Swap flips between DEV and LIVE, and Overlay surfaces a Diff control so you can isolate changes on a phone too.

Rebuild these screenshots from the deterministic local showcase:

npm run docs:screenshots

What it does

  • One view switch — Split (divider) · Solo (one pane, Swap flips) · Overlay (stacked). In Overlay an opacity slider blends the panes and Diff (mix-blend-mode: difference) lights up only the changed pixels. Overlay force-locks scrolling so the panes can't drift. Keys: O overlay, D diff.
  • Locked scrolling with one controller (exact pixel or proportional) — no duplicate scrollbars, no bounce. An internal link click mirrors to both panes.
  • Metadata diff + response details — title / description / canonical compared across sides (≠ meta). Each 200/3xx/4xx/5xx/ERR badge shows the response time on hover; click it for DEV/LIVE response, DOM-ready, load, transfer, headers, and deltas.
  • SEO panel — Google-style snippet preview + a ~13-point checklist per pane (title/description length, single H1, canonical, viewport, lang, Open Graph, noindex, image alt…), with a flag showing how many checks fail.
  • Review notes as a shared channel — author/route/side-tagged notes in a JSON file the viewer polls every 4s, so a teammate or an AI coding session can leave notes that appear live. Click a note to jump to its route, copy a per-note deep link, dock or float the drawer, and Send to vault or export Markdown.
  • No runtime dependencies. Node standard library only.
  • Deploy-preview mode for Cloudflare Pages. Preview branches can carry the compact comparison toolbar without changing production output or application API routes.

Keyboard

Key Action
O Toggle Overlay
D Toggle the Overlay difference blend
S Swap sides
R Reload both panes
0 Reset divider to 50/50
/ Focus the route field
Space / ⇧Space Page down / up (when scrolling is linked)
Line scroll both panes
Esc Close the notes drawer / open popovers

Shortcuts work whether focus is in the viewer chrome or inside either pane.


Options

Every option is a CLI flag, and also reads a SITEDRIFT_<NAME> env var.

Flag Env Default Purpose
-d, --dev <url> SITEDRIFT_DEV http://127.0.0.1:4321 Left-pane (dev) origin.
-l, --live <url> SITEDRIFT_LIVE required Right-pane (live) origin.
-p, --port <n> SITEDRIFT_PORT 4178 Listen port.
--host <addr> SITEDRIFT_HOST 127.0.0.1 Bind address.
--hostname <name> SITEDRIFT_HOSTNAME bind address Browser-facing local DNS name; the socket remains bound to --host.
-o, --open off Open the viewer in your browser.
--https off Serve HTTPS with an auto cert (mkcert if present, else openssl).
--setup-https One-time: generate + trust a local cert, then exit.
--http Force plain HTTP (the default; overrides --https).
--cert <file> / --key <file> SITEDRIFT_CERT / _KEY Bring your own cert; if both set, serve over HTTPS.
--notes <file> SITEDRIFT_NOTES $TMPDIR/sitedrift-notes.json Shared review-notes file.
--brand <text> SITEDRIFT_BRAND Strip | <text> from titles in pane headers.
--author <name> SITEDRIFT_AUTHOR you Byline for notes added in the viewer.
--vault <dir> SITEDRIFT_VAULT Enable Send to vault (writes the review markdown here).
--config <file> discovered Read project configuration from JSON.

A positional [path] (e.g. sitedrift /pricing) sets the initial route. -h, --help and -v, --version do what you'd expect.

AI and automation

The running process writes a private mode-0600 descriptor under ~/.sitedrift/sessions/. The npm package includes a zero-dependency stdio MCP server and an AGENTS.md operating guide.

Configure an MCP host with:

{
  "command": "sitedrift-mcp",
  "args": []
}

Codex and Claude Code can register it directly:

codex mcp add sitedrift -- sitedrift-mcp
claude mcp add sitedrift -- sitedrift-mcp

Without a global install:

{
  "command": "npx",
  "args": ["-y", "sitedrift", "mcp"]
}

Agents call sitedrift_context first, then use the note tools to share findings with the user. The server also exposes sitedrift://guide, a review_route prompt, and sitedrift_setup for install/config/HTTPS guidance.

sitedrift_notes_list returns an opaque revision. Pass that value to sitedrift_notes_watch to wait until notes change:

{
  "port": 4178,
  "revision": "6c12dbe41a39c2f7",
  "timeoutMs": 25000
}

The watch polls only inside the MCP tool call. A changed response contains the same notes payload as a normal list; an unchanged timeout returns only changed: false and the revision, avoiding repeated model-visible list output.

For hosts without MCP, use the JSON CLI instead of scraping the viewer or constructing authenticated requests:

sitedrift context
sitedrift notes list
sitedrift notes add "CTA differs" --route /pricing --side live --author codex
sitedrift notes resolve <id>
sitedrift notes reopen <id>
sitedrift notes remove <id>
sitedrift notes clear

Commands print JSON and return non-zero on failure. They work over HTTP or local HTTPS without an agent-specific SDK.

HTTP endpoints

Route Purpose
GET / The viewer.
GET /health { dev, live, version }.
GET /api/v1/session Authenticated session context and capabilities.
GET /api/v1/notes · POST /api/v1/notes Authenticated note list / operations.
GET /notes.md Notes as a Markdown checklist.
POST /api/v1/notes/save Write notes markdown into --vault.
GET /icon.svg The app mark / favicon.
frame ports: GET /__dev/* · GET /__live/* Isolated proxied origins.

The control API requires the per-session bearer token. The CLI commands above are the supported machine interface.

Most viewer state (route, layout, scroll mode, focus) is mirrored into the URL query string, so a link reproduces the exact view.


Security — local development only

The proxy strips Content-Security-Policy, X-Frame-Options, and the Cross-Origin-{Embedder,Opener,Resource}-Policy headers so production can be framed next to dev.

  • Only loopback hosts are accepted, and Host headers are validated.
  • The viewer/control API uses --port; DEV and LIVE frames use --port + 1 and --port + 2, so neither page can inspect the other.
  • Framed pages communicate through a narrow postMessage bridge and cannot access the viewer DOM, bearer token, notes API, or vault endpoint.
  • Treat the notes file as plaintext shared scratch space.

Development

npm test
npm run test:e2e:visual
npm run test:e2e:visual:update   # intentionally accept visual changes

The visual suite uses deterministic origins and checked-in Chromium baselines for desktop split, narrow Solo, difference overlay, and the notes drawer.

Limitations

  • URL rewriting is regex-based, tuned for static sites (e.g. Astro builds). It rewrites root-relative href/src/srcset/url(...) and Vite/_astro paths, but won't catch URLs built in JS (fetch, dynamic import, import maps). SPAs with client-side absolute fetches may need extra rules.
  • Designed for two origins of the same site, not arbitrary cross-site diffing.

Docs

Credits

Created by Joe Severino.

License

MIT © 2026 Joe Severino

About

Visual review for local and Cloudflare preview deployments — compare DEV and LIVE with Split, Overlay/Diff, SEO, response deltas, notes, and MCP.

Topics

Resources

License

Stars

Watchers

Forks

Contributors