BlogFindings
Can AI read my pricing page? 17 of 93 SaaS pricing pages put a price in the markup
Lantad requested the home page of the 130 SaaS hostnames in this repository's committed corpus on 22 September 2026, followed each site's own link to its pricing page and read the raw bytes with no JavaScript executed. 93 pricing pages answered with HTML. 77 of them showed a price in visible text and 17 declared one inside JSON-LD, and four of those 17 declared a price of zero on a page whose text listed paid plans.
So this is a measurement of both. On 22 September 2026 Lantad took the 130 SaaS hostnames in the committed industry corpus at worker/seeds/corpus-seeds-industry.json, requested each home page as LantadBot with redirects followed and no JavaScript executed, followed the site's own link to its pricing page, and read the bytes that came back. 93 pricing pages answered with an HTML content type. 77 of them carried a price a reader could see in the delivered text. 17 carried one a parser could lift from structured data. The gap between those two numbers is the finding, and the four sites that closed it by declaring a price of zero are the part worth reading twice.
In short
- Lantad followed the 130 SaaS hostnames in this repository's industry corpus to their pricing pages on 22 September 2026 and read the raw bytes with no JavaScript executed. 93 pricing pages answered with an HTML content type, and 17 of them carried a price, lowPrice or highPrice value inside JSON-LD.
- Can AI read my pricing page? On this corpus the text usually says yes and the markup usually says nothing: 77 of the 93 pages showed a price in visible text, and 61 of those 77 marked none of it up in a form a machine can lift.
- Four of the 17 pages carrying a price in markup declared only zero: auth0.com, dropbox.com, netlify.com and zapier.com on 22 September 2026, each on a page whose own visible text listed paid tiers above the free one.
- Google's SoftwareApplication structured data documentation, carrying Last updated 2026-09-08 UTC, lists offers.price among its required properties, and 7 of the 17 pages that declared any price used that type.
- Sixteen of the 93 pricing pages showed no price in visible text at all, and on jetbrains.com 144 currency tokens sat in the raw bytes while a non-rendering client read 8 visible words.
How the pricing page was found, and what that alone revealed
A pricing page has no well-known location. There is no specification that puts it at a fixed path the way the robots exclusion standard puts a file at /robots.txt, so finding one means doing what a crawler does: fetch the home page and follow a link. Each of the 130 hostnames received one request for its home page over HTTPS from one network location, with redirects followed and a twenty five second timeout. 119 answered with a 2xx status and an HTML content type. The other 11 did not, and the reasons matter for reading every figure below: seven answered HTTP 403 to this crawler, two answered 429, one answered 503 and one answered 404. Among the seven refusals were openai.com, oracle.com, akamai.com and servicenow.com, so the surviving set leans toward sites that admit an unknown crawler, exactly as it does whenever this blog counts what a scan was refused.
From each of the 119 home pages every anchor element was read and a link was taken as the pricing link when its href path segment or its anchor text named pricing, plans or prices, in English or in one of four other spellings the corpus contains. 90 of the 119 home pages carried such a link and 29 did not. For those 29 the conventional path /pricing was requested instead, and that guess is worth its own sentence because it failed so comprehensively: of the 29, five returned a usable page, two returned 403, and 22 returned HTTP 404. A convention that holds on five sites in twenty nine is not a convention. The result is that the pages measured here were almost all reached the way a crawler would reach them, by following a link the site chose to publish, which is the same dependency this blog measured when it counted how many home pages offered a crawler no internal path at all. Two of the 90 discovered links answered 403 and the remaining 88 answered with HTML, giving 93 pricing pages in total. Four of the 93 sat on a different hostname from the home page that linked them.
Flow: 130 SaaS hosts (2xx HTML) to 119 home pages in HTML; 130 SaaS hosts (403, 429, 503, 404) to 11 refused or failed; 119 home pages in HTML (anchor found) to 90 published a pricing link; 119 home pages in HTML (no anchor) to 29 got the /pricing guess; 90 published a pricing link (88 usable) to 93 pricing pages read; 29 got the /pricing guess (5 usable) to 93 pricing pages read; 29 got the /pricing guess (22 were 404) to 26 returned 404 or 403; 90 published a pricing link (2 were 403) to 26 returned 404 or 403.
Can AI read my pricing page?
On these 93 pages, a crawler that runs no JavaScript could read a price in the prose of 77 of them. That is the encouraging half and it is genuinely encouraging: the majority of these pricing pages are server rendered well enough that the numbers arrive in the bytes, which is not something this blog can say about every page type it has measured. When it counted the effect of client side rendering across a different frame, JavaScript supplied a measurable share of the prose. Here the prices mostly survive the fetch.
The second half is where the finding sits. 58 of the 93 pages carried at least one JSON-LD block. Only 17 carried a price, lowPrice or highPrice value anywhere inside it, and only 13 of those 17 carried a value above zero. So 41 pages published machine-readable markup on their pricing page and put no price in it, and 61 pages showed a reader a price while marking none of it up. The markup those 41 pages do carry is usually an Organization or a WebPage node, the same identity layer this blog found named no organization on 103 of 385 pages elsewhere in the corpus. It says who the company is. It does not say what the company charges.
That distinction is the whole reason the second number matters more than it looks. schema.org defines the price property of an Offer as "the offer price of a product, or of a price component when attached to PriceSpecification and its subtypes", which is an unambiguous assertion by the publisher about a specific thing. A figure in a paragraph is not. An engine that lifts "$19" from a sentence has to decide which plan it belongs to, whether it is monthly or annual, per seat or per account, and whether the adjacent "from" changes its meaning. That inference is exactly where a wrong answer comes from, and it is the same class of problem as the one behind a ChatGPT product feed requiring twelve fields rather than trusting a page to speak for itself. Marking the price up does not guarantee a citation, and this post does not claim it does. It removes the guess.
Four pages declared a price of zero while selling paid plans
Of the 17 pages that declared a price, four declared nothing but zero: auth0.com, dropbox.com, netlify.com and zapier.com. All four of those pages listed paid tiers in their visible text on the same day, and all four used the SoftwareApplication type. The mechanism is visible in the markup itself. Zapier's pricing page declares a SoftwareApplication with four Offer nodes named Free, Professional, Team and Enterprise. The Free node carries "price": "0" and "priceCurrency": "USD". The other three carry a name and a description and no price at all, and the Enterprise description ends "Contact for pricing". The visible text of the same page, read in the same request, contained $19.99, $69, $33.33 and $400 among others. Netlify's page does the same thing more briefly: a single Offer with "price": "0" and a description reading "Free tier available; paid plans for teams and enterprises", on a page whose text showed $9, $20 and $40.
Neither site has done anything careless, which is what makes this the interesting case rather than an error list. Google's SoftwareApplication documentation, carrying Last updated 2026-09-08 UTC, lists offers.price under Required properties and instructs that "if the app is available without payment, set offers.price to 0". A publisher with a free tier and four paid tiers has one required price field and five prices. Setting it to zero satisfies the requirement literally. What comes out the other end is a machine-readable statement that the product costs nothing, published on the page that exists to say what it costs, and there is no signal in the markup that the zero is a floor rather than the answer. This is the same failure shape as markup whose values are not on the page it describes: the syntax validates and the claim is wrong. The honest alternative is already in the vocabulary. Five of the 17 pages used AggregateOffer, which carries lowPrice and highPrice, and sentry.io declared lowPrice 0 and highPrice 960.00 on one node, which states the range instead of collapsing it.
| Site | Schema type used | Price values found | Highest declared |
|---|---|---|---|
| monday.com | Product with Offer | 23 | 52 |
| mongodb.com | Product with Offer | 9 | 57 |
| sentry.io | Product with AggregateOffer | 7 | 960.00 |
| typeform.com | Product with AggregateOffer | 7 | 266 |
| busy.in | SoftwareApplication with AggregateOffer | 6 | 22000 |
| bitrise.io | Offer | 5 | 600 |
| intercom.com | SoftwareApplication with Offer | 4 | 139 |
| livechat.com | SoftwareApplication with AggregateOffer | 4 | 79 |
| nordlayer.com | Product with Offer | 4 | 14 |
| asana.com | Product with Offer | 2 | 24.99 |
| gitlab.com | Product with Offer | 2 | 29 |
| ovhcloud.com | Product with AggregateOffer | 2 | 4355 |
| yoco.com | Product with Offer | 2 | 1499 |
| auth0.com | SoftwareApplication with Offer | 1 | 0 |
| dropbox.com | SoftwareApplication with Offer | 1 | 0 |
| netlify.com | SoftwareApplication with Offer | 1 | 0 |
| zapier.com | SoftwareApplication with Offer | 1 | 0 |
The 16 pages that showed a crawler no price at all
Sixteen of the 93 pricing pages carried no currency token in their visible text, and they divide into three causes that call for three different responses. The largest group is deliberate. Nine of the 16 carried contact-sales wording, among them snowflake.com, workday.com, databricks.com and outsystems.com, and on a page that genuinely refuses to publish a number there is nothing to mark up and nothing wrong. An answer engine asked what those products cost should say that the vendor does not publish it, and the page supports exactly that answer.
The second cause is a page that arrived empty. hubspot.com/pricing/marketing returned 74,787 bytes of HTML and 5 visible words, which were the words of its own title element. canva.com/pricing returned 58 visible words, and all of them were an unsupported browser notice telling the client to update to Chrome, Firefox, Safari or Edge. Neither page is refusing to state a price; both are stating it somewhere a non-rendering client never reaches, which is the condition the scanner grades as a prose parity failure and the reason the what GPTBot sees tool exists. A stack-specific version of the fix is on the React and Next.js pages.
The third cause is the one most likely to be mistaken for the second, and it is the most instructive. jetbrains.com/store returned 60,425 bytes containing 144 currency tokens, including $299.00, $239.00 and $24.92, and 8 visible words. The prices are in the delivered bytes. They are inside script elements, in the payload the page will hydrate from, so an extractor that drops script subtrees the way a browser's text layer does never counts them. This blog has measured that exact arrangement before and found that text in hydration JSON scored the same as no text at all, and the same pattern accounts for 1password.com/pricing/enterprise with 95 tokens in the bytes and none in the text, and webnames.ca with 60. Four of the 16 pages are in this state. A site in it is one template change away from parity, because the data has already been sent.
| Page | Visible words | Currency tokens in the bytes | Cause |
|---|---|---|---|
| hubspot.com/pricing/marketing | 5 | 0 | Empty to a non-rendering client |
| jetbrains.com/store | 8 | 144 | Prices in the hydration payload |
| canva.com/pricing | 58 | 0 | Unsupported browser notice |
| sinch.com/pricing | 597 | 0 | Contact sales |
| snowflake.com/en/pricing-options | 636 | 0 | Contact sales |
| webnames.ca/pricing | 671 | 60 | Prices in the hydration payload |
| 1password.com/pricing/enterprise | 707 | 95 | Prices in the hydration payload |
| freee.co.jp/pricing | 713 | 0 | No price in the delivered text |
| yoco.com/za/card-machines/pricing | 1,113 | 0 | Price in markup only |
| workday.com | 1,538 | 0 | Contact sales |
| elastic.co/pricing | 1,784 | 0 | Contact sales |
| outsystems.com/pricing-and-editions | 1,826 | 0 | Contact sales |
| databricks.com/product/pricing | 1,955 | 3 | Contact sales |
| teamviewer.com/en-us/pricing/overview | 2,647 | 0 | Contact sales |
| mekari.com/pricing | 3,184 | 0 | No price in the delivered text |
| misa.vn | 5,261 | 0 | No price in the delivered text |
What this measurement does not say
It describes 93 pages on one day. It does not describe what any named crawler does with them, because no request in this run came from GPTBot, ClaudeBot or PerplexityBot and none of those vendors documents how its fetcher treats an Offer node. Nothing here should be read as a claim that marking a price up produces a citation in ChatGPT or in Google AI Overviews. The claim is narrower and it is about legibility: a price inside an Offer is a statement a parser can take without inference, and a price in a sentence is not.
Five limits are worth stating plainly. 37 of the 130 hostnames produced no readable pricing page, 11 at the home page and 26 at the pricing page, and they are not absent at random, since a site that refuses an unknown crawler is likelier to refuse other automation too. Only one page per site was read, so nothing here describes a site's product pages, its documentation or its other templates. No JavaScript was executed, which is the point of the measurement rather than a shortcoming, but it means every figure describes what the server sent rather than what a browser eventually drew. A price was defined as a currency symbol or ISO code adjacent to a digit, which will count a figure that is not a plan price and will miss a price written in words, so the visible-text counts are an upper bound on precision rather than an exact inventory. And the corpus is an editorial sampling frame assembled for the crawlability study, so every rate here supports a statement about these 130 hostnames and nothing wider.
One more thing this run did not do is check whether the declared prices are correct. The table above reports what each site says about itself, not what it charges, and a blog post is dated while a price is not: any of these values may have changed since 22 September 2026. That is also the argument for reading them from markup rather than from a model's memory of a page, and it is why our own pricing is a page rather than a claim in an article. Anyone who wants the same two tests run against their own pricing page can get them from a scan, and the definitions behind the schema sub-score are set out on the methodology page and in the note on what structured data reaches ten million domains.
- The home page links to it 90 of 119 corpus home pages published a pricing link a crawler could follow. The /pricing guess failed on 22 of 29 sites that did not.
- It answers the crawler at all 26 of the 119 attempts ended in a 404 or a 403 rather than a page, before any content question was asked.
- The price is in the delivered bytes 77 of 93 pages carried a visible price. Four more carried the digits inside a hydration payload, where a text extractor does not reach them.
- The price is labelled as a price 17 of 93 declared one in JSON-LD. 61 pages showed a reader a number and marked none of it up.
- The declared price is the real range 4 of the 17 declared only zero. AggregateOffer with lowPrice and highPrice states a range, and 5 pages used it.
Lantad
Published .
A software company's price is one of the few facts about it that a person will ask an assistant for directly, and the pricing page is where the company states it. Stating it to a reader and stating it to a machine are two different jobs, though, and only one of them is obviously done. A reader sees a number in a plan card because a browser ran the site's JavaScript, laid out the card and drew the number. A crawler that fetches the page and executes nothing sees whatever the server put in the bytes, and a machine looking for a fact it can quote with confidence wants better than a number floating in a paragraph: it wants the number labelled as a price, attached to a named thing, in a vocabulary it already parses.
Common questions
Can AI read my pricing page?
It can read whatever the server sends. Of 93 SaaS pricing pages Lantad read on 22 September 2026 with no JavaScript executed, 77 carried a price in visible text, so most are legible as prose. Only 17 declared a price in JSON-LD, which is the form a parser can take without inferring which plan a number belongs to, and 16 carried no price in the visible text at all.
Does marking a price up in schema get my page cited by an AI assistant?
This measurement does not show that and does not claim it. No AI crawler vendor documents what its fetcher does with an Offer node, and no request in this run came from a named AI crawler. What markup removes is inference: an Offer with a price and a priceCurrency attaches a number to a named plan, where a figure in a sentence leaves the engine to decide whether it is monthly, annual or per seat.
Why did four sites declare a price of zero on a paid product?
Because Google's SoftwareApplication documentation, last updated 2026-09-08 UTC, makes offers.price a required property and says to set it to 0 if the app is available without payment. A product with a free tier and several paid tiers has one required field and several prices, so the zero satisfies the requirement and publishes a claim that the product costs nothing. AggregateOffer with lowPrice and highPrice states the range instead.
Is there a standard path for a pricing page like robots.txt has?
No. This run requested the conventional /pricing path on the 29 corpus home pages that published no pricing link, and 22 of those returned HTTP 404. A pricing page is found by following a link the site chose to publish, which makes the link itself part of whether the page is reachable at all.
See what AI can read on your site
Run a free scan and get a graded report of exactly what AI crawlers can and cannot read, with ranked fixes.