Comparing two URLs in the playground now compares their content, not their markup
The playground’s Compare two URLs mode used to run a line diff of both pages’ HTML, which on two different sites reports almost every line as changed. It now reads both pages into a content profile — title, meta description, h1, every h2 and h3, prices, call-to-action labels, length — compares those field by field, and shows the readable content of both pages side by side underneath.
Diffing a page against its own past works because the markup barely moves: the same template renders the same tree, and the handful of lines that changed are the change. Diffing two different sites is a different problem wearing the same clothes. One page is a Next.js tree of hashed class names, the other is an Elementor tree of `elementor-element-cd45e99` wrappers, and nothing lines up. Run the old compare over three real competitor pricing pages and it reports between 97.5% and 98.3% of lines as changed. The rendered diff is capped at 200 lines, so what a visitor actually saw was two hundred rows of red navigation markup, and the prices they came to compare were thousands of lines further down.
The compare mode no longer diffs markup at all. Both pages are read into a small profile and the profiles are compared field by field: page title, meta description, the `h1`, every `h2` and `h3` in page order, the prices on the page, the call-to-action labels, and the visible word count. Each row says whether the two sides are the same, differ, or exist on only one of them, and within the list rows every item the other page does not have is outlined — so on two pricing pages, the plan names and the amounts that only one side offers are the part that stands out.
Prices are currency-anchored on purpose. A bare number on a pricing page is a seat count, a retention window or a year far more often than it is a price, so an amount is only collected when it carries a symbol (`$`, `€`, `£`, `¥`, `₹`) or a currency code (USD, EUR, GBP, JPY, INR, PKR, CAD, AUD), or when it is declared in `[itemprop="price"]` markup or a JSON-LD `price`, `lowPrice` or `highPrice` field, in which case the accompanying `priceCurrency` is used to format it. Calls to action come from real buttons and button-styled links, plus any link whose text reads as an action, which is how a primary button styled with a class name no pattern could guess still gets found.
Before either page is read, site chrome is removed: `nav`, `footer`, `header`, `aside`, the matching ARIA landmark roles, dialogs and modals, anything `hidden` or `aria-hidden`, and any element whose class or id mentions cookies or consent. This is not tidying. Without it, a real comparison of two monitoring vendors reported "Accept all" and "Accept required" as one vendor’s calls to action and the heading of a hidden quote form as its `h1`. Removal is skipped when it would leave the page with under 200 characters of text, because some sites do put the whole body inside a `<header>`. What is left is then narrowed to the first of `main`, `[role="main"]`, `article`, `#content` or `#main` that holds real content.
Underneath the table, both pages are rendered as a readable outline and placed side by side: headings at their level, list items as bullets, quotes, and button labels, up to 140 lines per page. It is not an aligned diff and does not try to be — two marketing pages have no common structure to align against — it is there so that once the table has told you which fields differ, you can read what the other page actually says. Word count is reported in the table but deliberately not counted as a difference, since two pages of different length is the normal case rather than a finding.
Nothing else changed. Comparing two URLs still costs two of the five hourly checks because it is still two fetches, both bodies still land in the page cache so either side can be opened in the Extract fields tab for free, and the single-URL check and its Internet Archive diff still use the markup line diff, which is the right tool for the same page over time. When two URLs normalize to exactly the same text the comparison says so directly, which is the usual tell for a mirror or a redirect target.
- What it compares
- Page title, meta description, `h1`, every `h2` and `h3` (up to 24), prices (up to 10), call-to-action labels (up to 8), and visible word count.
- Why the old diff had to go
- Measured 97.5%–98.3% of lines changed across three real competitor pricing-page pairs, against a 200-line render cap.
- Price detection
- Amounts carrying `$ € £ ¥ ₹` or USD/EUR/GBP/JPY/INR/PKR/CAD/AUD, plus `[itemprop="price"]` and JSON-LD `price`, `lowPrice` and `highPrice` formatted by their `priceCurrency`.
- Stripped before reading
- `nav`, `footer`, `header`, `aside`, `[role="navigation"]`, `[role="banner"]`, `[role="contentinfo"]`, `dialog`, `[role="dialog"]`, `[aria-modal="true"]`, `[hidden]`, `[aria-hidden="true"]`, and any cookie or consent class or id — skipped if it would leave under 200 characters of text.
- Side-by-side content
- Both pages as a readable outline, up to 140 lines each, collapsed behind "Read both pages side by side".
- Cost
- Unchanged: 2 of the 5 hourly checks, and both fetched bodies stay cached for the Extract fields tab.