Skip to main content
ASoc
Tutorial

Generative Engine Optimization: Building a Site AI Answers Can Cite

An audit of our own site against the standard, including the two places it falls short and the checklist item we deliberately do not ship. The unit of success is a passage, not a page.

The ASoc Team12 min read

Generative engine optimization is the work of making a page quotable by an AI answer rather than clickable in a list of ten. The levers are different from classic SEO in one specific way: the unit of success is a passage, not a page. Everything below follows from that — self-contained answers, real numbers, and HTML that exists before JavaScript runs.

This is an audit of our own site against that standard, including the two places we fall short and the one popular recommendation we deliberately do not ship. It is worth saying at the top: we can verify what we emit, and we cannot yet verify what gets cited. Where a number below is ours it is measured; where it is borrowed it is attributed.

Start with the only hard requirement: the answer must be in the HTML

Every other tactic is downstream of this one. An AI crawler fetches a URL and reads what comes back. Some render JavaScript, some do it inconsistently, and none of them owe you a second pass.

So the first question is not about schema or headings. It is: what does curl see?

This storefront prerenders 111 product pages, 7 category hubs and 46 blog posts as static HTML. That is not a GEO tactic — it is how the site is built — but it is the thing that makes every tactic below possible. Two decisions in particular were made because of what a fetch-only reader sees:

The product carousel keeps every slide mounted. Virtualizing a four-slide gallery is the obvious optimization and it removes three of the four images from the document. Ours renders all slides into a translated track and moves a transform instead. The full pattern is its own post; the reason it is here is that "we render it, we just hide it with CSS" and "we render it when you click" are indistinguishable to a person and opposite to a crawler.

The related-products rail is a Server Component. Six sibling templates at the foot of every product page, rendered as plain links rather than reusing the interactive card. That was a bundle decision, and it has a second effect: the rail is in the HTML, so it is part of the page's link graph for a reader that never executes a line of JavaScript.

If you take one thing from this post, take the test rather than the tactics: fetch your own page with JavaScript disabled and read what is there. Most sites that "do not get cited" fail at this step, and no amount of schema fixes it.

The passage is the unit, so write passages

Classic SEO optimises a page to rank. Generative engines assemble an answer from fragments, so the thing you are optimising is a self-contained block that survives being lifted out of its context.

The convention we hold every post to, and have since the blog started:

  1. An answer block first. The opening paragraph answers the title's question in 40–60 words, before any preamble. That is the passage that gets quoted. Look at the top of this page — no throat-clearing, no "in today's fast-moving landscape".
  2. A comparison table wherever the topic has axes worth tabulating. A table is the most extractable structure there is: each row is a complete claim with its subject attached.
  3. A mistakes-and-symptoms table near the end. High-value for readers, and it answers a query shape ("why is X doing Y") that prose buries.
  4. An FAQ in bold-question format, three to five genuine questions. Question-shaped headings match question-shaped prompts.
  5. Real code, runnable, from how we actually build. Not pseudocode.

That spec is applied across all 46 posts. It is not a trick; it is the shape an answer takes when you write for someone who will read one screen of it.

The failure mode it prevents is the one most content has: a paragraph that begins "As we mentioned above, this approach…". Lift that out of the page and it means nothing. Every block in a quotable article has to name its own subject.

Original numbers are the differentiator

The most-cited finding in this field comes from the Princeton-led paper that named it — GEO: Generative Engine Optimization (Aggarwal et al., arXiv:2311.09735). It tested content modifications against generative-engine responses and reported that adding citations lifted visibility by around 40% and adding statistics by around 37%, while keyword stuffing reduced it. Those are their numbers, not ours — we have not reproduced the experiment.

But the mechanism is easy to believe from the other side of the desk: a model assembling an answer prefers a sentence it can attribute and check over a sentence expressing a preference. "Static rendering is faster" is unciteable. "Blocking every image and every prefetch on our home page moved LCP from 3786 ms to 3740 ms" is a fact with an owner.

This is the lever most sites cannot pull and you probably can. You are running something. Measure it and publish the number, including when it argues against you — the measurement above is on our own site and it undercuts the case for image optimization as a performance fix. Publishing it anyway is the reason that post is worth quoting.

The same logic makes comparison content disproportionately valuable: it is the format most likely to be asked for by name ("X vs Y"), and it forces per-axis claims rather than a narrative. Roughly a third of AI citations are reported to land on comparison-shaped articles in industry analyses — a figure we take on trust rather than having measured — but you do not need the statistic to see why the format wins.

What structured data does and does not do here

Schema is not a ranking signal for generative engines in the way it is for rich results. What it does is remove ambiguity: it tells a machine which string is the price, which is the publication date, which entity published the page.

Our full inventory, and what each is for:

WhereTypeJob
Root layoutOrganizationOne publisher identity across every page
Product pageProduct + AggregateOfferPrice and availability as data, not prose
Product pageSoftwareApplicationWhat the thing is, plus version and feature list
Product pageBreadcrumbListWhere it sits in a hierarchy a visitor can walk
Blog postBlogPostingHeadline, dates, author, publisher
Blog indexBlog with every blogPostThe whole archive from one URL
Pricing + hubsFAQPageQuestions as questions

Two rules we hold to, both of which matter more for AI answers than for rich results.

Never emit a claim the page cannot back. Product needs only one of offers, review or aggregateRating to qualify, so a truthful offer is sufficient and there is no reason to invent ratings. Our productLd returns null outright for a coming-soon product — advertising an offer that cannot be accepted is a false statement in machine-readable form, which is worse than no statement. The Product schema post covers the rich-result half.

Dates must be real. sitemap.ts stamps each product URL with its newest changelog date and each hub with the newest date among its products — never the build clock:

function productLastModified(product: TemplateProduct): Date {
  const newest = product.changelog[0]?.date;
  return newest ? new Date(`${newest}T00:00:00Z`) : new Date();
}

Telling a crawler that 100+ URLs changed on every deploy is a checkable false claim, and freshness is one of the few signals an answer engine can evaluate cheaply. Burn it and you have spent trust that was doing work for you.

The crawler question you have to answer on purpose

AI crawlers — GPTBot, ClaudeBot, PerplexityBot, Google-Extended and the rest — are governed by robots.txt like anything else. Which means there is a decision here whether you make it or not.

Ours is a wildcard allow, with only the account routes excluded:

rules: {
  userAgent: "*",
  allow: "/",
  disallow: ["/dashboard", "/login", "/signup", "/forgot-password", "/reset-password", "/auth"],
},
sitemap: `${BASE_URL}/sitemap.xml`,

That is a deliberate position for a business whose content exists to be found, and it is not the right position for everyone. If your content is the product, blocking the training crawlers while allowing the retrieval ones is a coherent stance — they are often separate user-agents, and worth separating in your rules rather than treating "AI" as one thing.

What is not coherent is blocking them by inheritance from a template and then wondering why you are not cited.

The recommendation we do not ship

llms.txt — a proposed markdown file at your root summarising your site for language models — appears on every GEO checklist. We do not ship one.

The reason is that we have no evidence any consumer reads it. It is a proposal, adoption is unconfirmed, and shipping a second copy of your site's structure creates a maintenance obligation that goes stale silently. Ours would need to track a 111-product catalog.

That said, the cost is genuinely low, and the honest position is uncertainty rather than dismissal: if you already generate a sitemap from typed data, generating a summary file from the same source is a small amount of code and it cannot hurt. What it should not do is displace the work above. A perfect llms.txt in front of a client-rendered site with no answer blocks is decoration.

Our functional equivalent is the machine-readable surface we already had a reason to build: a sitemap with honest dates, a Blog object listing every post from one URL, and a force-static RSS feed at /blog/feed.xml.

What we cannot measure, stated plainly

There is no Search Console for AI citations. We check target queries manually in a handful of assistants; that is a spot check, not measurement, and it does not survive being called a metric.

So the honest scoreboard is: we can verify the HTML, the schema, the dates and the crawl rules — all of which are checkable by anyone, including you, on our live site. We cannot yet tell you what share of answers cite us. Third-party monitoring tools for this exist and are improving; until one is wired in, treating "we implemented GEO" as a result rather than an input would be exactly the kind of unfalsifiable claim this post is arguing against.

Mistakes and how they show up

MistakeSymptomFix
Content rendered only after hydrationPage fetches empty; never quotedPrerender; test with JavaScript disabled
Carousel or tabs mounting one panel at a timeMost of the page invisible to a fetch-only readerRender all, hide with CSS
Opening paragraph is preambleNothing extractable at the topAnswer the title in 40–60 words, first
Passages that depend on earlier contextQuoted fragment means nothing aloneEvery block names its own subject
Opinions where numbers were availableUnciteable; loses to whoever measuredPublish your own figures, unflattering ones included
lastModified set to the build clockFreshness signal becomes noise, then ignoredDerive from real content dates
Schema asserting offers or ratings that do not existFalse claims in machine-readable formEmit null rather than a fiction
AI crawlers blocked by an inherited robots.txtAbsent from answers for reasons unrelated to contentDecide per user-agent, deliberately
Repeating the target keyword throughoutReported to reduce AI visibilityTitle, one heading, answer block — then write
Treating llms.txt as the strategyEffort spent where no consumer is confirmedFix the HTML first; add the file if it is cheap

Frequently asked questions

Is generative engine optimization different from SEO? The foundations are the same — crawlable, fast, well-structured pages — and Google's AI Overviews in particular draw on the same index as its classic results. What differs is the unit of optimisation. Classic SEO tunes a page to rank; GEO tunes a passage to be quoted. Most of the work is in how you write, not what you add.

Does structured data get me cited? Not directly, as far as anyone can demonstrate. It removes ambiguity about entities, prices and dates, which is worth doing anyway for rich results. Schema on a page whose answers are vague does nothing.

Should I block AI crawlers? It depends entirely on whether your content is marketing or product. If it exists to be found, blocking retrieval crawlers is self-defeating. If your content is the thing people pay for, blocking is defensible — and either way, make it a decision rather than a default inherited from a starter template.

How do I know if any of this is working? Imperfectly. Query a few assistants monthly with the questions your buyers actually ask and record whether you appear; watch referral traffic from assistant domains in your analytics. Both are weak instruments. Anyone selling certainty here is ahead of the evidence.

Do I need a blog for this? You need pages that answer questions. A blog is the conventional container, but a well-structured docs site, a pricing page with a real FAQ, or a comparison page can each be more quotable than a post — and a comparison page that names competitors honestly tends to be the single highest-value page a small site can publish.

Templates that ship the structure this needs

An AI product's marketing site is the hardest case: the design wants motion and demos, and the answers a buyer asks for — what it does, what it costs, how it works — need to be in the HTML as plain, self-contained blocks. The templates below take that shape, with capability sections, case studies, explainers and FAQ blocks as real prerendered content rather than as widgets that populate after hydration.

Keep reading

Tutorial8 min read

Building an HTML/CSS Navigation Bar (and the Bug That Hides It)

Six ingredients build an accessible nav bar — and this site's own mobile drawer shipped the pointer-events-none bug that leaves closed links keyboard-reachable.

Read more
Tutorial9 min read

HTML Nav: The Element, Not the Layout

A real production nav, from a 4-item desktop bar to a slide-out drawer — the aria-expanded toggle, the z-index stacking, and what a div-only navbar loses.

Read more