<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: IP</title>
    <description>The latest articles on DEV Community by IP (@ip1337).</description>
    <link>https://dev.to/ip1337</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3942324%2F8d588627-020a-45d3-8df4-cf9b8c292cf4.png</url>
      <title>DEV Community: IP</title>
      <link>https://dev.to/ip1337</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ip1337"/>
    <language>en</language>
    <item>
      <title>Make Your SaaS Product Page Quotable by an LLM: schema.org, llms.txt, and Stable URLs</title>
      <dc:creator>IP</dc:creator>
      <pubDate>Tue, 09 Jun 2026 12:54:00 +0000</pubDate>
      <link>https://dev.to/ip1337/make-your-saas-product-page-quotable-by-an-llm-schemaorg-llmstxt-and-stable-urls-400k</link>
      <guid>https://dev.to/ip1337/make-your-saas-product-page-quotable-by-an-llm-schemaorg-llmstxt-and-stable-urls-400k</guid>
      <description>&lt;p&gt;Here is a JSON-LD block that looks fine to a human and is useless to an LLM extractor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SoftwareApplication"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Analytics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"offers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Offer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"priceRange"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you build product pages and you care whether an AI assistant ever names your product in a discovery answer ("what's the best tool for X?"), this matters more than another homepage redesign. The block above fails for two concrete reasons: &lt;code&gt;priceRange&lt;/code&gt; is not a valid field on &lt;code&gt;Offer&lt;/code&gt; (it belongs on &lt;code&gt;LocalBusiness&lt;/code&gt;), and there is no &lt;code&gt;price&lt;/code&gt; or &lt;code&gt;priceCurrency&lt;/code&gt;. So an extractor asked "what does Acme cost?" has nothing to return, and the page gets dropped from the retrieval set for any pricing-shaped prompt.&lt;/p&gt;

&lt;p&gt;Here is the same block, fixed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SoftwareApplication"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Analytics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"applicationCategory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BusinessApplication"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"operatingSystem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Analytics is a web analytics tool for indie SaaS teams. It tracks product events and reports retention. Plans start at $19/month."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"offers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Offer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"19.00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"priceCurrency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four fields carry the weight: &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, and an &lt;code&gt;offers&lt;/code&gt; object with &lt;code&gt;price&lt;/code&gt; and &lt;code&gt;priceCurrency&lt;/code&gt;. That is the minimum machine-readable contract for a SaaS page that wants to be in an AI answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this decides whether you get recommended
&lt;/h2&gt;

&lt;p&gt;An assistant answering "what is the best X for Y" runs three stages: retrieve pages, extract facts, synthesize a shortlist. Structured data is what makes the extract stage succeed. A page with no schema, or broken schema, can survive retrieval and still get dropped before synthesis, because the model could not pull clean facts from it. The products that show up in the shortlist are the ones whose facts were extractable, not necessarily the ones with the best marketing. (This is a pattern worth internalizing if you've ever wondered why a worse-funded competitor keeps showing up in AI answers and you don't.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The three breaks worth auditing
&lt;/h2&gt;

&lt;p&gt;These pass loose validators and fail in practice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;priceRange&lt;/code&gt; on &lt;code&gt;Offer&lt;/code&gt;.&lt;/strong&gt; Only valid on &lt;code&gt;LocalBusiness&lt;/code&gt;. Use &lt;code&gt;price&lt;/code&gt; + &lt;code&gt;priceCurrency&lt;/code&gt; on &lt;code&gt;Offer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing &lt;code&gt;offers&lt;/code&gt; entirely.&lt;/strong&gt; A &lt;code&gt;SoftwareApplication&lt;/code&gt; with no offer cannot answer cost questions. Add it even for free products (&lt;code&gt;"price": "0"&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raw URL strings where an object is required.&lt;/strong&gt; &lt;code&gt;ListItem.item&lt;/code&gt; and &lt;code&gt;InteractionCounter.interactionType&lt;/code&gt; should be a full &lt;code&gt;Thing&lt;/code&gt; / &lt;code&gt;IdReference&lt;/code&gt;, not a bare URL string. Google tolerates the loose form; strict parsers reject it. Also: &lt;code&gt;ImageObject.width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt; must be strings or &lt;code&gt;QuantitativeValue&lt;/code&gt;, never raw numbers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Validate with a strict, typed builder instead of eyeballing. In TypeScript, &lt;code&gt;schema-dts&lt;/code&gt; makes the compiler reject hallucinated fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WithContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SoftwareApplication&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;schema-dts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ld&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WithContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SoftwareApplication&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SoftwareApplication&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Acme Analytics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;applicationCategory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BusinessApplication&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;offers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Offer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;19.00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;priceCurrency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you put a field that does not belong on &lt;code&gt;SoftwareApplication&lt;/code&gt;, this fails to compile. That is the point: it catches the made-up fields that loose JSON validators wave through. (This is the exact approach we landed on building product listings at &lt;a href="https://peerpush.com" rel="noopener noreferrer"&gt;PeerPush&lt;/a&gt;, after enough hand-written JSON-LD drifted out of spec.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Test what actually ships, not what you think ships
&lt;/h2&gt;

&lt;p&gt;Client-rendered JSON-LD can vanish from the served HTML, and CSS-driven spacing can mangle text nodes that an extractor reads. Check the raw response, not the browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://yoursite.com/product/acme | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'application/ld+json'&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://yoursite.com/product/acme &lt;span class="se"&gt;\&lt;/span&gt;
  | python3 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"import sys,re,json; [json.loads(m) for m in re.findall(r'&amp;lt;script type=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;application/ld&lt;/span&gt;&lt;span class="se"&gt;\+&lt;/span&gt;&lt;span class="s2"&gt;json&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;(.*?)&amp;lt;/script&amp;gt;', sys.stdin.read(), re.S)]; print('all JSON-LD blocks parse')"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a block does not parse, it is invisible to extractors, which is worse than having none.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ship llms.txt
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;llms.txt&lt;/code&gt; is an emerging convention: a plain-text file at your site root that describes your site and lists key pages for AI retrieval. It is not yet required by any assistant, but it is cheap to ship and a reasonable hedge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Acme Analytics&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Web analytics for indie SaaS teams. Plans from $19/mo.&lt;/span&gt;

&lt;span class="gu"&gt;## Key pages&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; /product: what Acme does
&lt;span class="p"&gt;-&lt;/span&gt; /pricing: plans and prices
&lt;span class="p"&gt;-&lt;/span&gt; /alternatives: how Acme compares
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Stable URLs are part of the contract
&lt;/h2&gt;

&lt;p&gt;A slug that changes on a rebrand drops you out of the retrieval set until the new URL re-indexes. Assign slugs once, hold them forever, and &lt;code&gt;301&lt;/code&gt; anything you must move, keeping the redirect alive indefinitely. Protect three URLs above all: your product page, &lt;code&gt;/pricing&lt;/code&gt;, and any &lt;code&gt;/alternatives&lt;/code&gt; or &lt;code&gt;/vs&lt;/code&gt; page. Treat changes to those as migrations, not casual edits.&lt;/p&gt;

&lt;h2&gt;
  
  
  A first paragraph that extracts
&lt;/h2&gt;

&lt;p&gt;Extractors weight the opening of a page heavily. Open each page with a complete factual claim: what the product is, who it's for, what it costs, in plain English. Replace "Discover the future of analytics" with "Acme Analytics is a web analytics tool for indie SaaS teams; plans start at $19/month." Concrete sentences get quoted; vague ones get dropped.&lt;/p&gt;

&lt;h2&gt;
  
  
  The checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;code&gt;SoftwareApplication&lt;/code&gt; JSON-LD with &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, and &lt;code&gt;offers&lt;/code&gt; (&lt;code&gt;price&lt;/code&gt; + &lt;code&gt;priceCurrency&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;[ ] No &lt;code&gt;priceRange&lt;/code&gt; on &lt;code&gt;Offer&lt;/code&gt;; no raw URL strings where objects are required; image dims as strings.&lt;/li&gt;
&lt;li&gt;[ ] Validate with &lt;code&gt;schema-dts&lt;/code&gt; (or the Schema.org validator) in CI.&lt;/li&gt;
&lt;li&gt;[ ] First paragraph of each page is a complete factual claim, not a tease.&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;llms.txt&lt;/code&gt; at the root.&lt;/li&gt;
&lt;li&gt;[ ] Stable slugs; &lt;code&gt;301&lt;/code&gt;s held indefinitely for the product, pricing, and alternatives pages.&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;curl | grep&lt;/code&gt; the served HTML to confirm the JSON-LD actually ships.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is a product change. It is the difference between a page an assistant can quote and one it silently skips, and it's almost entirely under your control as the person who owns the markup.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>agents</category>
    </item>
    <item>
      <title>How to Structure a SaaS Product Page So AI Assistants Can Recommend It</title>
      <dc:creator>IP</dc:creator>
      <pubDate>Thu, 21 May 2026 07:42:32 +0000</pubDate>
      <link>https://dev.to/ip1337/how-to-structure-a-saas-product-page-so-ai-assistants-can-recommend-it-3h02</link>
      <guid>https://dev.to/ip1337/how-to-structure-a-saas-product-page-so-ai-assistants-can-recommend-it-3h02</guid>
      <description>&lt;p&gt;Most SaaS product pages in 2026 are structured for human eyes and Google's old keyword crawler. They render fine in a browser, they score well on Lighthouse, they have a &lt;code&gt;/blog&lt;/code&gt; and a &lt;code&gt;/pricing&lt;/code&gt; and a &lt;code&gt;/about&lt;/code&gt;. And they are nearly invisible to ChatGPT, Claude, Perplexity, and Gemini when a user asks "what is the best tool for X." This post is the technical playbook for closing that gap.&lt;/p&gt;

&lt;p&gt;PeerPush, the indie SaaS directory at &lt;a href="https://peerpush.net" rel="noopener noreferrer"&gt;https://peerpush.net&lt;/a&gt;, builds every product listing around the same primitives covered below. The advice applies whether a product gets listed on PeerPush or not. The structure is what matters.&lt;/p&gt;

&lt;p&gt;The TL;DR: AI assistants synthesizing a "best X for Y" answer fetch pages, parse facts off them, and rank candidates by the volume and quality of extractable structured data. Make your facts extractable, on stable URLs, with the right schema.org annotations, and the assistant has what it needs to recommend you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AI engines need structured data
&lt;/h2&gt;

&lt;p&gt;A frontier AI assistant fielding a product recommendation question runs roughly this pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Retrieve:   fetch pages relevant to the user's query
2. Extract:    pull discrete facts (name, price, features, integrations, audience, tradeoffs)
3. Synthesize: build a ranked shortlist and a justification paragraph
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The extraction step is where most product pages fail. A page that says "We help your team scale operations with our intuitive platform" is invisible. A page that says "Acme Tasks is a project management tool for engineering teams of 3-30. Free plan with 5 users. Paid plans start at $12/user/month. Integrates with GitHub, Linear, Slack" is the page the assistant cites.&lt;/p&gt;

&lt;p&gt;Structured data formats give the model explicit hooks for the extraction step. The most important ones for SaaS are JSON-LD with schema.org's &lt;code&gt;SoftwareApplication&lt;/code&gt;, &lt;code&gt;Offer&lt;/code&gt;, &lt;code&gt;FAQPage&lt;/code&gt;, and &lt;code&gt;BreadcrumbList&lt;/code&gt; types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schema.org primitives every SaaS product page needs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SoftwareApplication with Offer
&lt;/h3&gt;

&lt;p&gt;The minimum viable JSON-LD for a SaaS product page in 2026:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SoftwareApplication"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Tasks"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"applicationCategory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BusinessApplication"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"operatingSystem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Web, iOS, Android"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Project management for engineering teams of 3-30. Async-first, GitHub-integrated, opinionated about cycle time."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acmetasks.example/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"offers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Offer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Free"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"priceCurrency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Up to 5 users, unlimited tasks, no SSO"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Offer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"priceCurrency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Per user / month, unlimited users, SSO, audit log"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things matter here that most product pages get wrong:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;offers&lt;/code&gt; must contain &lt;code&gt;price&lt;/code&gt; and &lt;code&gt;priceCurrency&lt;/code&gt; as primitive values&lt;/strong&gt;, not as &lt;code&gt;priceRange: "$12-$48"&lt;/code&gt;. AI extractors and Google's rich result parsers both reject &lt;code&gt;priceRange&lt;/code&gt; on &lt;code&gt;Offer&lt;/code&gt; (it's only valid on &lt;code&gt;LocalBusiness&lt;/code&gt;). Multiple price points = multiple &lt;code&gt;Offer&lt;/code&gt; entries in an array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;description&lt;/code&gt; does double duty.&lt;/strong&gt; It is what the assistant pulls when summarizing your product. Write it as a single noun-phrase sentence that names who the product is for, not as marketing copy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A common mistake: putting the &lt;code&gt;@type&lt;/code&gt; as &lt;code&gt;Product&lt;/code&gt; instead of &lt;code&gt;SoftwareApplication&lt;/code&gt;. &lt;code&gt;Product&lt;/code&gt; is for physical goods. SaaS is software. Google and the major AI extractors weight &lt;code&gt;SoftwareApplication&lt;/code&gt; correctly; &lt;code&gt;Product&lt;/code&gt; confuses the classification.&lt;/p&gt;

&lt;h3&gt;
  
  
  BreadcrumbList for category context
&lt;/h3&gt;

&lt;p&gt;If your product page lives at &lt;code&gt;/products/acme-tasks&lt;/code&gt; under a category tree like &lt;code&gt;/categories/project-management&lt;/code&gt;, give the assistant the path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BreadcrumbList"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"itemListElement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ListItem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"item"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acmetasks.example/categories/project-management"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Project Management"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ListItem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"item"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acmetasks.example/products/acme-tasks"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Tasks"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: &lt;code&gt;item&lt;/code&gt; must be a full &lt;code&gt;Thing&lt;/code&gt; object with &lt;code&gt;@id&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt;, not a raw URL string. Google's documentation shows both shapes; some AI extractors only accept the strong-typed form. Use the strong-typed form.&lt;/p&gt;

&lt;h3&gt;
  
  
  FAQPage for "common questions" extraction
&lt;/h3&gt;

&lt;p&gt;When a user asks "does Acme Tasks support SSO," the assistant wants a Q&amp;amp;A pair it can pull verbatim. The &lt;code&gt;FAQPage&lt;/code&gt; schema gives it one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FAQPage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mainEntity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Question"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Does Acme Tasks support SSO?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"acceptedAnswer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Answer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Yes. SAML SSO and SCIM provisioning are available on the Pro plan and above. Free plan users authenticate with email + password or Google OAuth."&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Question"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What is Acme Tasks priced at?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"acceptedAnswer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Answer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Free for up to 5 users. Pro is $12 per user per month, billed annually. Enterprise is custom."&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five to ten Q&amp;amp;A pairs per product page is the sweet spot. Cover pricing, integrations, the most common "does it support X" questions, and at least one objection ("how does this compare to [competitor]").&lt;/p&gt;

&lt;h2&gt;
  
  
  The llms.txt file pattern
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;llms.txt&lt;/code&gt; is the AI-era equivalent of &lt;code&gt;robots.txt&lt;/code&gt;. It is a plain Markdown file at the root of your domain (&lt;code&gt;https://yourdomain.example/llms.txt&lt;/code&gt;) that gives AI crawlers and assistants a curated index of your most important public URLs.&lt;/p&gt;

&lt;p&gt;A minimum useful &lt;code&gt;llms.txt&lt;/code&gt; for a SaaS product:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Acme Tasks&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; Project management for engineering teams of 3-30. Async-first, GitHub-integrated, opinionated about cycle time.&lt;/span&gt;

&lt;span class="gu"&gt;## Core pages&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Pricing&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://acmetasks.example/pricing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: full plan breakdown with real prices
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Integrations&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://acmetasks.example/integrations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: supported and not-supported integrations
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Documentation&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://acmetasks.example/docs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: how the product works
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Changelog&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://acmetasks.example/changelog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: what's shipped recently

&lt;span class="gu"&gt;## Comparisons&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Acme Tasks vs Linear&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://acmetasks.example/alternatives/linear&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: when each is the better choice
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Acme Tasks vs Jira&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://acmetasks.example/alternatives/jira&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: tradeoffs and migration notes

&lt;span class="gu"&gt;## Posts AI assistants might find useful&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;How we think about cycle time&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://acmetasks.example/blog/cycle-time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: opinion piece, 2026-01-15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file is not a standard yet (the proposal is at &lt;code&gt;llmstxt.org&lt;/code&gt;). It works in practice because AI crawlers and grounded retrieval systems are increasingly opportunistic about consuming Markdown indexes when they find them. Cost to ship: 30 minutes once, then keep current. Upside: a small structured nudge that tells AI infrastructure which URLs matter most.&lt;/p&gt;

&lt;h2&gt;
  
  
  URL stability: redirects, canonicals, sitemap discipline
&lt;/h2&gt;

&lt;p&gt;The compounding effect of being in AI training corpora rests on URL stability. Every URL killed is a citation killed.&lt;/p&gt;

&lt;p&gt;Three rules that pay back over months:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Never just delete a page.&lt;/strong&gt; Use 301 redirects when restructuring. If a feature is sunset, leave the page up with a "this feature is no longer supported, here is the current alternative" notice and link to the replacement. The URL is what AI engines remember; the content can change underneath it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Canonical tags on every product page&lt;/strong&gt;, pointing to the version you want indexed. Especially important if you syndicate content to dev.to, Hashnode, or Medium (which is exactly what this post is doing, by the way: the canonical of this article is &lt;a href="https://peerpush.net/blog/2026-indie-saas-launch-playbook" rel="noopener noreferrer"&gt;https://peerpush.net/blog/2026-indie-saas-launch-playbook&lt;/a&gt;, declared in the &lt;code&gt;canonical_url&lt;/code&gt; frontmatter dev.to reads).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;sitemap.xml&lt;/code&gt; discipline.&lt;/strong&gt; Submit it via Google Search Console. Update it on schedule. AI training pipelines often hit &lt;code&gt;sitemap.xml&lt;/code&gt; as a seed for discovering a site's structure; an up-to-date sitemap with a &lt;code&gt;&amp;lt;lastmod&amp;gt;&lt;/code&gt; per URL signals which pages are current.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to test if your changes worked
&lt;/h2&gt;

&lt;p&gt;A practical loop for testing whether AI assistants are picking up your changes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Pick 5-10 questions a real user might ask in your category. Examples for a project management tool: "What is the best project management tool for engineering teams?" "What are alternatives to Linear?" "Does Jira have a free plan?"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run each question through ChatGPT (paid), Claude (free), Perplexity (free), and Gemini (free). Record whether your product is mentioned, at what position in the answer, and which competitors are mentioned alongside.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Repeat the same prompts weekly. Single-week deltas are noise. The trend over 6-12 weeks tells you whether the structured data work is moving the needle.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;PeerPush runs a daily version of this loop internally to measure AI citation rate. The same loop works for any product team that cares about being recommended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes that kill AI extraction
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hiding pricing behind "Contact sales."&lt;/strong&gt; The pricing page is the first page assistants fetch when asked about cost. No numbers = no recommendation in cost-sensitive answers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;description&lt;/code&gt; written as marketing copy.&lt;/strong&gt; Use noun phrases that name who the product is for and what it does, not adjective phrases that describe how it feels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single huge JSON-LD blob that doesn't validate.&lt;/strong&gt; Google's Rich Results Test (&lt;code&gt;search.google.com/test/rich-results&lt;/code&gt;) catches schema errors. If it doesn't pass there, AI extractors built on similar parsers won't pass either.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generic "alternatives" page with no real tradeoffs.&lt;/strong&gt; A page that says "we're better than [competitor] in every way" is not the page assistants cite. The page that says "[competitor] is the better choice if you need X, but here is when we are" is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robot.txt blocking AI crawlers without thinking it through.&lt;/strong&gt; Some SaaS sites block GPTBot, ClaudeBot, etc. in &lt;code&gt;robots.txt&lt;/code&gt; to "protect content from AI training." That choice trades short-term content protection for long-term invisibility in AI recommendations. Worth thinking about explicitly rather than blocking by default.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What to ship this week
&lt;/h2&gt;

&lt;p&gt;A practical checklist, in priority order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Audit your product's &lt;code&gt;/pricing&lt;/code&gt; page. Are there real numbers, real plan names, real trial terms? If not, fix that first.&lt;/li&gt;
&lt;li&gt;Add JSON-LD with &lt;code&gt;SoftwareApplication&lt;/code&gt; + &lt;code&gt;Offer&lt;/code&gt; to the homepage and the pricing page.&lt;/li&gt;
&lt;li&gt;Build one &lt;code&gt;/alternatives-to-&amp;lt;competitor&amp;gt;&lt;/code&gt; page with the comparison-table pattern from earlier in this post.&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;FAQPage&lt;/code&gt; JSON-LD block with 5-10 questions on the homepage or a dedicated FAQ page.&lt;/li&gt;
&lt;li&gt;Ship &lt;code&gt;llms.txt&lt;/code&gt; at the root of your domain with the format shown above.&lt;/li&gt;
&lt;li&gt;List the product on three directories that fit your category. PeerPush at &lt;a href="https://peerpush.net/submit" rel="noopener noreferrer"&gt;https://peerpush.net/submit&lt;/a&gt; is one option among several; others include BetaList, AlternativeTo, SaaSHub.&lt;/li&gt;
&lt;li&gt;Set up the test loop described above and check it weekly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most of this is implementable in a single afternoon. None of it depends on a viral launch day. All of it compounds in AI training corpora over the next 24+ months.&lt;/p&gt;

&lt;p&gt;The new shelf is permanent. The structured data is the door key.&lt;/p&gt;




</description>
      <category>ai</category>
      <category>agents</category>
      <category>programming</category>
      <category>aeo</category>
    </item>
  </channel>
</rss>
