Data Downloads: CSV and JSON
Every record page on Caliper Press has two files next to it: data.json with the full record and data.csv with one row per check. Each section page has the same two files with the latest check of every record in the section, and an Atom feed of confirmed changes. There is no API, key or sign-up: the files are static, free to download and updated daily.
Where the files are
Add data.json or data.csv to the address of a record page or a section page. Each of these pages also links to its files at the bottom. One example per section:
| Section | Records | Example files |
|---|---|---|
| Domain registration and renewal prices | 39 | data.json · data.csv (Dynadot .com) |
| SaaS pricing tracker | 130 | data.json · data.csv (Asana Starter) |
| Web hosting and VPS prices: first term vs renewal | 47 | data.json · data.csv (DigitalOcean Basic Droplet 1 GiB) |
| Post-quantum TLS checks | 60 | data.json · data.csv (Cloudflare) |
| VPN pricing, renewal and refund terms tracker | 28 | data.json · data.csv (AdGuard VPN) |
| AI bot access policies | 60 | data.json · data.csv (BBC) |
The coverage page lists the sections and how many records each has. The renewal costs page also has a data.csv with its table.
Three formats of data.json
object_slice, plan_slice, section_slice
The schema field at the top of every data.json names its format, and each format has a JSON Schema (draft 2020-12) to validate against:
object_slice: a record page, such as /vpn/objects/ipvanish/. One record with all its checks. object_slice.jsonplan_slice: a plan page, such as /saas-prices/objects/asana-starter/. One row per billing option; each row holds a full record in the object_slice format underrows[].slice, so the history of a row is inrows[].slice.history. plan_slice.jsonsection_slice: a section page, such as /saas-prices/. Every record of the section with its latest main check, without history. section_slice.json
Fields of a record (object_slice)
9 fields, and what each check holds
object: what is tracked, with its id (object_id, written as section:record), name, section and the provider page we read.latest: the last confirmed check of the main question. Newer checks that recorded no value are listed inheld_valuefor up to 3 days; after thatlatestis the newest check, with the value unknown.history: every check of the record, oldest first, up to and includinglatest.indicators: values we calculate from the checks, each with its window and sample size (n).events: confirmed changes, each with the old and new value, when it was first seen and when it was confirmed.raw_journal: moves that were not counted as changes, with the reason, for example a value that did not repeat in the next check.quarantine: large price moves held back until a repeat check confirms them; the held number itself is not published.held_value: questions where the page shows the last confirmed value because newer checks recorded none.billing, on hosting, domain and VPN records: how the first term is paid, as the provider's page states it.
Each check in latest and history has:
questionin plain words andtimein ISO 8601;measured:value,unitand, for money,currency; an answer in words is intext;claim: what the provider's page states, withsource.url, a shortsource.quoteand thedate;data_status:measured,stated_by_source,calculatedorunknown, shown on pages as Observed, Published by the source, Calculated and Unknown;region, the two-letter code of the country the value was shown in, andregion_name;method_version, the edition of the method, andevidencewithurl,bytesandhttp_status.
Numbers are decimal strings, such as "2.99", so no precision is lost. An unknown value is null with a reason, never zero. Units are codes such as usd_per_month, usd_per_year or days; the schemas list every code.
Fields of a plan and a section
plan_slice and section_slice
A plan file (plan_slice) has plan_id, name, main_object_id (the row whose price is the plan's main answer), rows, the events of all rows and related answers from other records of the same plan. Each row has billing (annual or monthly), promo, object_id, purchase_payment (what is paid at purchase and how many months it covers) and slice.
A section file (section_slice) has objects, one entry per record with object_id, name, the page url, plan and latest; index, the section's index value when it has one, with its range (lowest and highest contribution) and participants (the records counted); license and generated_at.
Reading the files: an example
a short Python script
This Python script prints every check in a record file or a plan file:
import json, urllib.request
url = "https://caliperpress.com/saas-prices/objects/asana-starter/data.json"
d = json.load(urllib.request.urlopen(url))
if d["schema"] == "plan_slice":
records = [row["slice"] for row in d["rows"]]
else:
records = [d]
for r in records:
for c in r["history"]:
m = c["measured"]
print(r["object"]["object_id"], c["time"], m["value"], m["unit"])What data.csv contains
one row per check
A record file has one row per check, with the columns object_id, measurement_id, time, value, unit, status, method_version, source and currency. A plan file adds billing after object_id. A section file has the same columns, one row per record with its latest check. The renewal costs CSV has one row per plan, with its first-term price, renewal price and the date.
Change feeds
Atom, for the whole site and each section
changes.xml is an Atom feed of confirmed changes across the site, newest first. Each section page has its own feed: add changes.xml to its address, as in /saas-prices/changes.xml. Each entry links to the change on its record page.
Using the data
CC BY 4.0, with credit
Our numbers are licensed under CC BY 4.0 with attribution to Caliper Press. Credit the page you used and the date of the data; how to use this data shows a citation format. Quotations from provider pages are short excerpts that belong to their owners and are not covered by our license.
A record keeps its address when new checks are added, and earlier checks stay in history.
What is not available
no API keys, bulk archive or email alerts
There is no API with keys, no bulk archive of the whole site and no email alerts. The free tools on this site call small endpoints under /api/ for their own pages; those are not a data service and can change without notice.