Dev.to AI 🤖 Ai 👁 0 📖 6 min read

It Worked Locally… But Did It Match Staging? Meet DiffLens

DiffLens: Compare Local and Staging Web Apps with Visual, Content, and Markup Diffs Have you ever finished a UI change, opened staging, and wondered: “What exactly changed between my local build and staging?” A manual

It Worked Locally… But Did It Match Staging? Meet DiffLens

DiffLens: Compare Local and Staging Web Apps with Visual, Content, and Markup Diffs

Have you ever finished a UI change, opened staging, and wondered: “What exactly changed between my local build and staging?”

A manual check can miss small layout shifts, changed text, or unexpected DOM updates. I built DiffLens to make those differences easier to inspect.

DiffLens is a local web app that compares a local page against a staging page in three independent ways:

  • Visual diff: Which pixels changed?
  • Content diff: Which visible text changed?
  • Markup diff: Which elements or attributes changed?

DiffLens — Compare. Understand. Ship with confidence.

The DiffLens dashboard: configure the local and staging pages, then launch a comparison. The capture and comparison workflow runs locally.

The problem: a screenshot does not tell the whole story

A screenshot comparison is useful, but it only answers part of the question.

  • A button may have moved by a few pixels.
  • A heading may have changed.
  • A link may look identical but point to a different URL.
  • A DOM node may have been added without an obvious visual change.

These are different kinds of changes, so DiffLens treats them as separate comparison layers.

1. Visual diff

DiffLens captures both pages using Chromium at a fixed 1920 × 1080 viewport, then compares the screenshots using pixelmatch.

Changed pixels are highlighted over a faded local screenshot. The UI provides side-by-side, slider-overlay, and diff-only views.

Side-by-side mode makes it easy to inspect the original local and staging captures before drilling into individual changes.

Overlay mode places both captures on top of each other. Drag the divider to reveal each version and spot alignment or layout shifts.

Diff-only mode isolates changed pixels. Large highlighted areas can indicate content or layout shifts, while smaller regions can reveal styling changes.

The comparison summary also reports the percentage of pixels that differ. Treat this as a signal for investigation rather than a pass/fail score: dynamic content, font rendering, and page movement can all affect the result.

2. Content diff

The content layer compares visible page text (innerText) line by line using the diff library. Adjacent delete/add pairs are presented as word-level modifications.

Staging is the baseline; local is the candidate:

  • Added: Content present in local but absent from staging.
  • Removed: Content present in staging but absent from local.
  • Edited: Existing content whose wording has changed.

The content view explains what changed in the page copy, with additions, removals, and edited wording highlighted inline.

3. Markup diff

The markup layer compares element snapshots matched by rendered CSS path. It reports new nodes, removed nodes, text changes, and tracked attribute changes such as href, src, alt, aria-*, and form attributes.

How it works

Both URLs are loaded in parallel in isolated browser contexts, so cookies and browser storage are not shared between sides.

Before capture, DiffLens blocks service workers, freezes animations and transitions, waits for fonts and images, and scrolls the page to trigger lazy-loaded content. It captures visible text, element snapshots, console/network diagnostics, and screenshots.

The three diff layers then run and their results are assembled into a report.

flowchart TD
    A[Local URL] --> C[Chromium capture]
    B[Staging URL] --> D[Chromium capture]
    C --> E[Local snapshot]
    D --> F[Staging snapshot]
    E --> G[Visual diff]
    F --> G
    E --> H[Content diff]
    F --> H
    E --> I[Markup diff]
    F --> I
    G --> J[Comparison result]
    H --> J
    I --> J
    J --> K[HTML report and JSON]

Both pages use the same capture settings:

Setting Value
Viewport 1920 × 1080
Device scale factor 1
Locale en-US
Colour scheme light
Reduced motion Enabled

Implementation notes

DiffLens uses Chromium because visual comparison requires actual layout and paint. The Chromium build is installed for Playwright. pixelmatch powers screenshot comparison, while the diff library handles text comparison. Markup comparison uses captured element snapshots.

Visual comparison

The visual layer compares the two captured screenshots and identifies changed pixels.

// Conceptual example of the visual comparison stage.
const changedPixels = pixelmatch(
  stagingImageData,
  localImageData,
  diffImageData,
  width,
  height,
  { threshold: pixelThreshold }
);

Content comparison

The content layer compares captured visible text, treating staging as the baseline and local as the candidate.

// Conceptual example.
const changes = diffLines(stagingText, localText);

Markup comparison

For markup, DiffLens captures each element's CSS path, tag, own text, and tracked attributes. The snapshots are matched by CSS path to identify additions, removals, and updates.

These snippets illustrate the approach; they are not copied from the project's internal modules.

Diagnostics and comparison details

A visual or content difference is easier to investigate when you can also see how each page loaded. DiffLens includes a Diagnostics view with information for both sides, including HTTP status, page title, viewport, page height, visible text size, scanned element count, links/buttons/images, capture time, and console or request errors.

More than a screenshot comparison

Per-side headers and cookies

Headers and cookies can be configured independently for local and staging. This is useful for pages behind authentication or feature flags.

Basic Auth

DiffLens supports preemptive Basic Auth on each side independently. Static comparisons pass credentials to Playwright through httpCredentials.

Passwords are not persisted to localStorage, sent to the server, or included in exported artifacts. The UI stores only the username for display, and the password field is cleared after the session ends.

Exportable results

Each comparison produces a self-contained HTML report with embedded screenshots and a JSON result. Screenshots, text snapshots, and result.json are stored under .artifacts/<id>/; the latest 40 runs are retained.

Try it locally

Requirements

  • Node.js 20+
  • macOS, Linux, or Windows
  • Approximately 150 MB for the Chromium build

Installation

git clone https://github.com/praveen-pravi6B/difflens.git
cd difflens
npm install
npm run setup:browser
npm start

Open http://127.0.0.1:4173 and select Try the demo. The bundled demo pages contain intentional differences so you can explore all three comparison layers.

To compare your own pages, enter a local URL such as http://localhost:3000 and a staging URL such as https://staging.example.com. Select Compare pages, or use ⌘ + Enter on macOS / Ctrl + Enter on Windows and Linux.

Useful commands

npm start               # Start the application
npm run dev             # Restart on file changes
npm run setup:browser   # Install Chromium
npm run smoke           # Run the end-to-end smoke test

Limitations and security

  • Dynamic content such as timestamps, A/B tests, live counters, and carousels can differ between captures.
  • Full-page pixel diffs on long pages can be affected by vertical layout shifts.
  • Canvas, WebGL, and video cannot be meaningfully compared as text or DOM.
  • Bot protection may serve different content to headless Chromium.

DiffLens fetches the URLs you provide, including internal hosts. It binds to 127.0.0.1 by default. Do not expose it to an untrusted network without adding authentication and appropriate SSRF protections. Only HTTP and HTTPS URLs are accepted.

What's next?

The next step for DiffLens is synchronized live rendering. Instead of comparing captured screenshots, this mode will render the local and staging pages side by side in the same workspace, so you can interact with both versions while reviewing them.

The planned experience will include:

  • Side-by-side view: see the local and staging pages next to each other.
  • Slider view: use a draggable divider to reveal either page in a shared viewing area.
  • Synchronized interactions: click a link or navigation item in one pane and the corresponding navigation action will happen in the other pane too. This makes it easier to follow the same user journey on both versions and compare the result as you go.

This will build on DiffLens's existing comparison workflow by making it easier to inspect not only what changed in a capture, but also how both versions behave during the same interaction.

If you work on frontend applications, QA, or UI testing, give it a try and let me know what would make it more useful.

Project:

GitHub logo praveen-pravi6B / difflens

Compare a local web app against staging using Chromium, showing visual, content, and markup differences. Supports live mirrored mode with single-tab split view, Basic Auth per-origin, and automated diff comparison.

DiffLens

DiffLens

Compare. Understand. Ship with confidence.

Compare a local web app against staging and see exactly what changed — visually, in the text, and in the markup.

Visual diff · Content diff · Markup diff


Why DiffLens?

DiffLens is a local web app for reviewing changes between a local build and a staging environment. It renders both pages in Chromium at the same 1920 × 1080 viewport, then produces three independent comparisons:






















Comparison What you get
Visual Full-page pixel comparison. Changed pixels are highlighted over a faded local screenshot. Inspect side-by-side, slider-overlay, or diff-only views.
Content Visible text compared line by line, with word-level highlights for modified lines. Staging is the baseline; local is the candidate.
Markup DOM elements matched by rendered CSS path, including added and removed nodes, text changes, and tracked attribute changes such as href, src, and alt.

Every comparison also produces a self-contained…




If you find it useful, consider starring the repository, opening an issue, or contributing an improvement.

DiffLens — Compare. Understand. Ship with confidence.

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.