Visual Checks vs Lightweight Checks
When DiffHook checks a webpage, it can do it in two very different ways. The mode you pick controls accuracy, cost, and the kinds of changes you'll detect.
This page explains the trade-off so you can pick the right mode for each monitor — or update your workspace default in Settings → Team → Monitor defaults.
TL;DR
| Lightweight check | Visual check | |
|---|---|---|
| What it does | Downloads the raw HTML, no scripts run | Opens the URL in a real headless Chromium, runs all scripts, takes a screenshot of the rendered page |
| Counts against | Monthly lightweight checks | Monthly visual checks |
| Speed | Fast (~hundreds of ms) | Slow (seconds, full page load) |
| Cost | Low | ~10–100× higher per check |
| Catches text/markup changes | Yes | Yes |
| Catches JavaScript-rendered changes | No | Yes |
| False positives on dynamic pages | Possible | Rare |
If you only need to watch a snippet of HTML on a static page (RSS feed, sitemap, server-rendered article, JSON API) — use a lightweight check. If the page is a single-page app, a dashboard, a price that loads after the page does, or anything that looks broken when you "View Source" in your browser — use a visual check.
How lightweight checks work
DiffHook issues a single HTTPS request and reads the response body up to a hard cap. That's it. Whatever the server returns is what we compare against the previous snapshot.
This is exactly how curl or wget see a page. It's how Google's first crawlers worked for years, and it's still the cheapest, fastest, most reliable way to detect a change — as long as the change is in the HTML that's served.
Great for:
- Server-rendered blog posts, news articles, marketing pages
- RSS / Atom feeds
- Sitemaps
- JSON APIs (price feeds, status endpoints, public CMS APIs)
- Any page where the meaningful content is in the initial HTML response
Bad for:
- React / Vue / Angular / Svelte single-page apps
- E-commerce sites where the price is fetched by JavaScript after the page loads
- Dashboards with content rendered from a backend API call
- Pages whose first-paint HTML is mostly empty (
<div id="root"></div>and not much else) - Sites that aggressively gate content behind JavaScript challenges
How visual checks work
DiffHook opens the URL in a real Chromium browser, lets it execute all JavaScript, waits for the page to settle (network-idle + auto-scroll to flush lazy-loaded content), and takes a full-page screenshot.
We then compare that screenshot — pixel by pixel for visual monitors, or by the rendered HTML for text/selector monitors — against the previous snapshot.
This catches almost everything a human visitor would notice. It's also dramatically more expensive: every check spins up a headless browser, pays the latency of a real page load, and is metered against your visual check monthly quota (separate from your lightweight check quota).
Use it for:
- Anything that doesn't work with a lightweight check (see above)
- Full-page visual monitors where you care about layout, images, or rendered output
- Pages where you can't reliably target a stable CSS selector
- E-commerce, real-time data, JS-heavy SaaS apps
False positives & flakiness
Both modes can be noisy, in different ways.
Lightweight checks are noisy when the HTML contains things that change every request even though the content didn't change — CSRF tokens in hidden inputs, A/B-test variant classes, build hashes in script URLs, dynamic ad markup. The cure is a precise selector (css:, jsonld:, $.field) so we only watch the bit that matters.
Visual checks are noisy when the rendered page itself changes on every load — a clock, a "users online" counter, animated hero images, randomized testimonials. The cure is either a tighter crop region, a CSS-selector scope to a stable section, or a longer polling interval so transient changes don't fire alerts.
Pricing
Visual checks are billed against a separate monthly quota from lightweight checks:
| Plan | Lightweight checks / mo | Visual checks / mo |
|---|---|---|
| Free | 2,500 | 250 |
| Starter | 15,000 | 2,000 |
| Pro | 150,000 | 10,000 |
| Business | 750,000 | 50,000 |
Extra visual checks are sold as add-ons: $30 for every 10,000 extra checks per month, with volume discounts above 100K/mo. See Plans & Billing for the full add-on tier table.
How to pick a mode
On a single monitor (API) — set html.js_rendering to true (visual check) or false (lightweight) when calling POST /api/monitors. The API flag name stays js_rendering for backwards compatibility:
{
"label": "Product page price",
"url": "https://example.com/products/widget",
"html": { "js_rendering": true }
}
On a single monitor (UI) — when you create a visual monitor without picking a specific element, DiffHook asks once how to render it and remembers your choice for next time.
Workspace default — change the saved preference any time in Settings → Team → Monitor defaults. The default applies to new uncropped visual monitors created from the UI. The per-monitor html.js_rendering flag always wins over the workspace default.
Preview calls are free
The POST /api/monitors/preview and POST /api/monitors/visual-preview endpoints — used by the create-monitor UI when you paste a URL — never count against your check credits, regardless of mode. Only real, scheduled monitor runs are metered.