
What AI Assistants Read on Your Pricing Page (and Why Hiding the Number Hides the Product)
A growing share of "what should I use for X?" questions never reach a search results page anymore. They go to an assistant. Someone types "best transcription tool under $15 a month" into ChatGPT, Perplexity, Claude, or Google's AI overview, and the model answers with a short list of named products and, increasingly, their prices.
Here is the part most founders miss: the assistant can only put your product on that list if it can read your price. Not infer it. Not guess from a "starts at" badge buried in a carousel. Read it, as a number, attached to a plan, on a page it can fetch.
If your pricing lives behind a "Contact sales" button, inside a JavaScript widget that only renders after a click, or as an image of a table, you are not in the running for any price-qualified question. The model has nothing to quote, so it quotes someone else.
This post is about the mechanics of that. What an AI extractor actually pulls from a pricing page, the specific patterns that make a price unreadable, and the small set of changes that put a quotable number in front of the models. None of it requires a redesign.
The question has a number in it
Start with the demand side. A large and rising fraction of buying-intent prompts are price-qualified. People do not ask "best project management tool" as often as they ask "best project management tool for a team of five under $50 a month" or "cheapest alternative to Tool X that still does Y."
Those qualifiers are not noise. They are the filter. When an assistant assembles its answer, it is doing a retrieval-and-rank pass over what it knows and what it can fetch, and the price constraint prunes the candidate set hard. A product the model cannot price is a product it cannot confidently include in a price-bounded answer, because including it risks a wrong claim. Models hedge away from wrong claims about money. So they drop you.
This is the asymmetry worth sitting with: being cheaper than the competitor does not help if the model cannot see your number. The competitor who published a plain "$12 per user, per month" wins the "under $15" slot, even if you are $9 behind a contact form. Visibility beats value when the reader is a machine that refuses to guess.
What an extractor actually pulls
When an AI system reads a pricing page, it is not experiencing your layout. It is parsing a document. Strip the CSS and the animations and you are left with text and, if you provided it, structured data. An extractor is looking for a few specific things:
- A plan name. "Starter," "Pro," "Team," "Business." The label that the price attaches to.
- A number and a currency. Not "$" floating near "29" two divs away. A contiguous, parseable amount with a currency it can resolve to USD, EUR, GBP, and so on.
- A billing period. Per month, per year, per seat, one-time. A bare "$29" with no period is ambiguous, and ambiguity gets discarded or hedged.
- What the number includes. A short, factual line about what the plan covers. This is what lets the model say "the $12 plan includes unlimited projects" instead of just naming a figure.
- A free tier or trial signal, if one exists. "Free plan available" and "14-day free trial" are themselves answers to a whole class of prompts ("free tools for X"), and they are frequently missed because they live in a toggle or a footnote.
Two sources feed those five fields: the visible prose on the page, and the structured data in the page's markup. The prose is what most extractors fall back on. The structured data is what the careful ones prefer, because it is unambiguous. Publishing both is the difference between "probably $29 a month" and a price the model will state without hedging.
The patterns that make a price unreadable
Most pricing pages that fail do so for one of a small number of reasons. Each one is a self-inflicted blind spot.
The contact wall. "Contact us for pricing" is, to a retrieval system, the absence of a price. There may be excellent commercial reasons to gate enterprise pricing, but if every tier is gated, the product has no machine-readable price at any point, and it falls out of every price-qualified answer. If you must gate the top tier, publish a real number on at least one lower tier so the product is priceable at all.
The price that only exists after a click. Plenty of pricing pages render the actual numbers through a framework that only hydrates the figures after a toggle (monthly versus annual) or a region selector fires. If the price is not in the HTML that comes back from a plain fetch, a large share of extractors never see it. Server-render at least one default price into the initial markup.
The price as an image. A beautifully designed pricing table exported as a PNG is invisible. Optical character recognition is not reliably in the path for most extractors, and even when it is, you have handed the model a low-confidence guess instead of text. Numbers belong in text nodes.
The number split from its meaning by layout. "$" in one element, "29" in another, "/mo" in a third, separated for styling. To a human with the CSS applied, that reads as "$29/mo." To a parser reading the stripped document, those can land as three disconnected tokens. Keep the amount and its period in the same readable string.
The "starts at" badge with no detail. "Plans start at $9" on the homepage, with the real breakdown living somewhere a crawler has to hunt for, gives the model a floor and nothing else. It cannot answer "what does the $9 plan include," so it cannot recommend you for anything specific.
The common thread: each pattern optimizes for a human eye with full CSS and full interactivity, and forgets the second reader, who has neither.
The fix is a readable number and a little structured data
The remedy is not a redesign. It is making sure a price exists as plain, parseable text, and then backing it with structured data so the careful extractors get an unambiguous version.
Step one: put a real number in the initial HTML. For at least one plan, render the amount, the currency, and the billing period as text that is present before any JavaScript runs. You can verify this in seconds. Fetch your own pricing page the way a crawler would and look at the raw markup:
curl -s https://yourdomain.com/pricing | grep -iE '\$[0-9]|per month|/mo|priceCurrency'If your prices do not show up in that output, neither do they show up for a large share of the systems deciding whether to recommend you. That single command is the most honest pricing-page audit you can run.
Step two: keep the amount and period together. Write the price as one contiguous string a parser cannot misread:
$12 per user, per monthrather than splitting the symbol, the number, and the period across three separately-styled elements. Style the parts with spans inside that string if you need to, but keep the readable text intact.
Step three: add Offer structured data. For a software product, the schema.org type is SoftwareApplication, and the price lives in an offers block. A minimal, valid example:
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Your Product",
"applicationCategory": "BusinessApplication",
"operatingSystem": "Web",
"offers": {
"@type": "Offer",
"price": "12.00",
"priceCurrency": "USD"
}
}A few things to get right here, because they are the common breaks. Use SoftwareApplication, not Product; Product is the schema for physical goods, and AI extractors and search engines treat software differently. Include both price and priceCurrency; a price with no currency is not actionable. Do not put priceRange on an Offer; that property belongs to a LocalBusiness, and validators reject it on an Offer. If you genuinely have no fixed price, that is a signal to publish a representative starting tier rather than to omit offers entirely, because an offer-less software entry is one a model cannot price.
Step four: make the free-or-trial signal explicit. If you have a free plan or a trial, say so in plain words near the prices ("Free plan available" / "14-day free trial, no card required") and reflect it in the structured data. "Free tools for X" and "X with a free trial" are entire prompt categories, and they are won by the products that state the fact plainly rather than hiding it in a toggle.
Step five: write one factual line per plan. Under each price, put a single sentence of what the plan includes, written as a complete claim rather than a marketing tease. "The $12 plan includes unlimited projects and up to ten teammates" is quotable. "Everything you need to scale" is not, because it answers no specific question.
The standalone first paragraph, applied to pricing
There is a broader principle underneath all of this that is worth naming, because it generalizes past pricing pages. AI extractors reward content where a single passage can stand alone as an answer. On a pricing page, that means the sentence around each price should be self-contained. A reader, or a model, should be able to lift "Starter is $12 per user per month and includes unlimited projects" out of the page and have it make sense with no surrounding context.
Most pricing copy fails this because it is written to be read top to bottom with the visual hierarchy doing the work. The number is big, the inclusions are a checklist of icons, the period is a small-grey toggle. Visually elegant, semantically scattered. Rewriting just the few sentences around each price so each one is a complete factual claim is a small edit with an outsized effect on how quotable the page is.
How to check whether it worked
You do not have to wait and wonder. There are three cheap checks.
The curl | grep from above tells you whether the number is in the raw HTML at all. Run it first; it catches the most common failure.
A structured-data validator (Google's Rich Results Test, or any schema.org linter) tells you whether your Offer is well formed and whether the price and currency are present. Worth noting that the Rich Results Test is more permissive than some AI extractors, so passing it is necessary but not sufficient; the curl check covers the gap.
And the direct test: ask a few assistants a price-qualified question that your product should win ("best [your category] under $X a month") and see whether you appear. Repeat it across a couple of models, because they differ. If you are absent from a question you should clearly win on price, the problem is almost never that you are too expensive. It is that the model could not read your number.
Where this fits
The pricing page is one surface in a larger shift. Product discovery is moving from leaderboards and search results toward assistants that answer in named, qualified recommendations, and the products that win those recommendations are the ones a machine can read without guessing. Clean, published, structured pricing is one of the highest-leverage pieces of that, because price is the single most common qualifier in buying-intent prompts and the single most commonly hidden field.
This is part of why a structured product directory is useful at all. We work on PeerPush, where products are described with normalized, machine-readable fields including pricing, so that assistants answering "best tool for X under $Y" have a clean source to draw from. It is one way to get a quotable price in front of the models; publishing one on your own pricing page, the way described above, is another, and the two reinforce each other. Neither replaces the basic discipline of putting a real number in the HTML.
The takeaway is small enough to act on this afternoon. Open your pricing page, run the curl | grep, and if your price is not in the output, fix that one thing first. Everything else on this list is an improvement. That one is the difference between being on the list and not.