Structured data and retrieval
schema-truth
Checks whether the prices, ratings, reviews, authors, dates and FAQ answers in a page's JSON-LD are shown in the text visitors see on that page.
- Kind
- Open-source tool
- Language
- JavaScript
- License
- MIT
- Status
- First release
- cli
- jev
- json-ld
- schema-org
- seo
- structured-data
- typesafe
Markup that drifts from the page
Google's structured data policies rule out marking up content that readers of the page cannot see. Markup drifts all the same: a sale changes the price on the page but not in the JSON-LD, a plugin keeps last year's FAQ answer, a rating count comes from another system. Schema validators check that the markup is well formed and has the required properties; they do not compare its values with the page. A string match cannot tell that "2 March 2026" on the page is the 2026-03-02 in the markup, or that the price in the markup is the struck-through one next to a sale price. schema-truth asks about each value and flags the ones the visible text does not support.
Code reads the page, Jev compares
Code does the reading. For each page, schema-truth extracts every JSON-LD block, follows @graph and @id links, and turns the values worth checking into claims:
- offers: price with its currency, lowest and highest price, list price, availability;
- ratings and reviews: the average, the number of ratings and reviews, each review's author and rating;
- articles, blog posts and events: headline, author, published and modified dates, start and end dates;
- FAQ and Q&A pages: each question and its accepted answer;
- organisations and local businesses: address and phone number.
It also extracts the text a visitor sees, leaving out scripts, styles, the <head>, templates, inline SVG, closed dialogs and anything with the hidden attribute or an inline display: none. Image alt text is kept, and table cells are joined so a row reads as one line.
Then comes one request per page. The visible text is the state, and each claim is one yes or no question for Jev, TypeSafe AI's System One model, with the claim passed as data next to a fixed question: is this value supported by the text a visitor sees? Before a value is sent, code rewrites ISO dates in words and availability URLs as words ("in stock"), because TypeSafe's notes on jev-1.13 advise doing such conversions in code rather than leaving them to the model.
The verdict is made in code with one threshold, 0.8 by default: supported at or above it, unsupported at or below 0.2, and review in between, for a missing answer, or for a page with no visible text in its HTML. A page with more than about 16,000 tokens of visible text is sent in parts, each with every claim, and a claim counts as supported when any part shows it.
Fetching pages without trusting them
It fetches only http and https URLs. Before connecting, it resolves the host name and checks every address it gets back: loopback, private, link-local, cloud metadata and other reserved ranges, IPv4 and IPv6, are refused, including addresses written into the URL itself. The connection then goes only to the addresses that passed, and the same checks run on every redirect, at most three. Each page has a 10-second limit and at most 2 MB of HTML. For a page on your own network, save it from your browser and pass the file.
TypeSafe receives the visible text and the claims, never the page's URL, its raw HTML or the JSON-LD blocks themselves. The exit code is 1 when a claim is unsupported, so it can fail a CI job.
Limits
- It reads the HTML as served. Scripts do not run, so content a script adds is missed, and stylesheets are not loaded, so text hidden only by a CSS class, such as a closed accordion, counts as visible.
- Only JSON-LD: microdata and RDFa are not read, and brand, SKU, opening hours, images and breadcrumb names are not checked.
- "Unsupported" means the visible text does not show the value. How much that matters depends on the property: a price or a review the page does not show is a bigger problem than a modified date.
- Jev reads numbers and dates as text and the tool does no arithmetic, so a rating shown as a percentage or a price in another currency usually goes to review.
- Text written to steer a model, in the page or in the markup, can move Jev's answers. English is where it is most accurate.
- The example in the repository is three short pages for a made-up shop, with hand-written probabilities: it shows the report's format, not a live run.
Install and run
It needs Node.js 20 or later and has no dependencies.
npm install -g github:hamzaahmadaslam/schema-truth
export TYPESAFE_API_KEY=<your-key>
schema-truth saved-pages/ --dry-run
schema-truth https://shop.example/a https://shop.example/b
Related
Related work on this site
- Custom WordPress developmentCustom WordPress themes, Gutenberg blocks and ACF editing workflows. Build a site around your content, integrations, accessibility and performance needs.Service
- stale-claimsFinds the claims in documents that are true only for a while, such as versions, dates, statistics and roles, and give no as-of date, before they reach an index.Open source