Skip to content
PricingAlmanac.com

Methodology

How the figures get here, what happens when a read goes wrong, and the rules that decide whether a page is allowed to exist at all.

Last reviewed

This page describes the system as it is built, not as it is intended. The thresholds quoted below are imported directly from the code that enforces them, so if one changes, this page changes with it in the same commit.

1. Collection

A crawler identifying itself as PricingAlmanacBot reads each vendor's own published pricing page on a schedule. It reads first-party pages only: the vendor's site and nothing else. Review sites, competitor comparison pages and third-party aggregators are never sources here, because a figure copied from another aggregator inherits that aggregator's mistakes and its staleness while looking exactly as confident as a real reading.

Requests are spaced at least 3 seconds apart per host with at most 2 in flight, robots.txt is honoured, and each vendor is given a stable offset within the nightly window so the whole set does not arrive at one minute. Conditional requests are used, so a vendor whose page has not changed answers with a small "not modified" response and no page is re-downloaded. The crawler page covers this from a vendor's point of view, including how to block it.

Every response body that produced a figure is archived for 90 days. That copy is the evidence: when a value here is disputed, the question is what the page said on the day it was read, and a live re-fetch cannot answer it.

2. Extraction, and how confident it is

Values are extracted through a ladder, tried in order, most reliable first. Which rung produced a given value is recorded and published in the provenance table on the page that displays it.

JSON-LD
Structured data the vendor publishes for search engines. The vendor stated the number in machine-readable form; there is nothing to interpret.
Embedded JSON
The data the vendor's own page uses to render itself, read from the page source. Not authored for us, but not guessed either.
Microdata
Structured markup inline in the HTML, read the same way.
Page selector
A rule written by hand against that specific vendor's page structure — a price under a named plan heading, for instance. Reliable while the layout holds, and it announces itself loudly when the layout changes, because the rule stops matching entirely rather than matching the wrong thing.
Heuristic
A last resort: pattern-matching prose for a currency amount. Values from this rung are capped below the confidence needed to publish automatically, so in practice they surface a gap rather than fill one.

A plan carries the confidence of the weakest rung that contributed to it, not the strongest. A price read cleanly from JSON-LD does not launder a seat limit that was guessed from a sentence.

3. What happens when a read goes wrong

Scrapers break constantly, and the dangerous failure is not the one that crashes — it is the one that returns a plausible wrong number. Four rules exist for that, and all four bias towards keeping the last known-good value over accepting a new one.

  • A failed read never overwrites good data. If a page will not parse, the previous value stays live with its original verification date, and the failure is recorded against the adapter rather than against the product.
  • A large move quarantines instead of writing. A price moving more than 60% in a single observation is held. The previous value stays on the site until the new one is confirmed by a second, independent observation at least 20 hours later — spacing that matters, because two reads from the same broken vendor deploy would otherwise confirm each other.
  • An implausible shape is rejected wholesale. If the extracted tiers come back in an impossible order — a cheaper plan priced above a dearer one — the run is rejected in full. Nothing is written, because a misread page structure means every value from it is suspect, not just the obviously wrong one.
  • A quiet adapter is treated as a broken one. Each adapter is scored on the proportion of expected fields it actually filled, tracked against its own trailing history. A drop is escalated whether or not anything threw.

There is also a circuit breaker over the whole dataset: if too large a share of live pages would disappear in a single run, or too many adapters are failing at once, nothing publishes at all and an alert is raised instead. Publishing a broken dataset is unrecoverable in a way that skipping a day never is — the wrong price is cached, indexed and screenshotted long before any correction catches up.

4. Freshness

A verified figure does not stay verified, and this site does not let one age quietly. Every price carries the date it was read, and every page carries the most recent verification behind anything on it.

Verified within 14 days
Published, labelled with the date. Each individual datapoint's own verification timestamp appears in the provenance table, so a page whose figures were read on different days shows that rather than averaging it away.
Older than 14 days
The page is not published. It is withdrawn from the sitemap and stops being built, and it returns only when a fresh reading arrives. There is no intermediate state where a price older than this is displayed with a caveat attached — a stale price served confidently is worse than no price, and a caveat is not enough to fix it.

This is stricter than it needs to be, deliberately. The cost of withdrawing a page is that a reader finds nothing; the cost of keeping it is that a reader finds a number that is wrong and has no way to know. Those are not comparable, so the cut is made early and without a grace period.

5. What gets computed

The computed figures are the reason these pages exist; without them a pricing page here would be a slower copy of the vendor's own. All of them are deterministic arithmetic over the recorded numbers — no model, no weighting, no scoring.

  • Normalised monthly cost. Monthly, annual, quarterly and one-time billing collapsed to one comparable monthly figure. One-time charges are amortised over 36 months, which is a stated assumption rather than a fact, and it is printed alongside anything derived from it. Usage-only plans return no figure and say why, rather than a fabricated zero.
  • Cost at seat counts. What each plan costs a team of 1, 3, 5, 10, 25, 50, 100 people, taking included seats, minimums and maximums into account. A plan that cannot serve a team of that size is shown as unavailable rather than as a price it would never charge.
  • Crossover seat count. The team size at which one product stops being cheaper than another. This is the single most useful number on a comparison page and it appears on no vendor's site, because no vendor has both sides of it.
  • Cheapest tier with a given feature, and the dollar premium between the cheapest tier without it and the cheapest tier with it. "SSO is on the Business plan" is a fact; "SSO costs you an extra amount per seat per month" is the same fact in the units the decision is actually made in.
  • Price history. Change over trailing windows, the date of the last change, and how many times a price has moved. Suppressed until there is enough observation history for the answer to mean anything — before that, "unchanged" only means "we have not been watching long".

Prose on data pages is assembled from these numbers by formatters. There is no language model anywhere in the pipeline, which is a hard rule rather than a current preference: it is what makes every claim on the site traceable to a number and a citation.

6. Which pages are allowed to exist

Pages are not generated for everything that could have one. Each candidate is tested against a gate, and a page that fails is not created — not created thin, not created with a "coming soon" notice, not created at all. The gate runs once, when the dataset is exported, so a page that failed it is physically absent from the data the site is built from.

A pricing page

  • At least 2 plans, or one plan carrying at least 6 recorded features
  • At least 6 features with known values
  • At least 3 computed figures
  • At least 2 cited sources
  • Every displayed price verified within the freshness window

A comparison page

  • Both products in the same category
  • At least 8 features with known values on both sides — otherwise the comparison is mostly blanks
  • At least 3 of those actually differing. Two products with identical published feature sets are not a distinct answer to a distinct question
  • At least 2 computed differentiators
  • A cap of 12 comparison pages per product, chosen deterministically as its nearest neighbours by price, feature similarity and prominence

That last cap is the most consequential rule in the system. Comparing every product with every other would turn 200 products into nearly 20,000 pages, the overwhelming majority of them pairings nobody would ever type — which is exactly the pattern search engines now treat as scaled content abuse. The cap is a deliberate ceiling on how large this site can become, and raising it is not a growth strategy.

7. Corrections

Figures here are read automatically and can be wrong. The provenance table on every data page is there so a wrong one can be checked in a single click, and reporting an error takes a link and a sentence. Corrections are the most useful thing anyone sends; hello@pricingalmanac.com reaches a person.

The data sources page lists every vendor page this site reads and links the machine-readable dataset for each product.