WorkServicesBlogTalksAboutBook a call
Content

The technical GEO stack: what your website needs to get cited by AI

The advice circulating about how to get cited in AI Overviews, ChatGPT, Claude, and Perplexity tends to fall into two camps: vague ("be authoritative and helpful!") or repetitive ("add FAQ schema and structure your content!").

Both are fine. Neither is the full picture.

What's consistently missing is the technical layer: the configuration that makes your website legible to AI systems before they read a single word you've written. A brilliantly written page is useless if AI crawlers can't access it, can't find it, or can't understand what it's saying beyond the text itself. The technical setup is what opens the door.

I recently rebuilt this site from scratch and did a thorough build of the GEO (Generative Engine Optimization) infrastructure as I went, documenting every decision. This post is that documentation turned into a practical guide: what I set up, why each part matters, and how to implement it regardless of your platform.

A note on certainty before we start. GEO is young, and a lot of the advice out there (including some below) is informed experiment, not proven fact. Some of this is well established: clean sitemaps, canonicals, fast pages, and structured data are long-standing SEO fundamentals, and they feed the same crawl-and-index pipeline AI search sits on top of. Some of it is emerging and unproven: llms.txt is an early proposal, not an adopted standard, and Google has publicly said its AI Overviews and AI Mode rely on ordinary search best practices and need no special AI-specific files or markup. I've tried to flag which is which as I go. Treat the newer items as low-cost, low-risk experiments worth running, not guarantees of citations.

How AI engines use your website

Before the checklist, a quick grounding in how this works, because it shapes every technical decision.

AI systems like ChatGPT, Perplexity, Claude, and Google AI Overviews use a few routes to find and cite your content:

Their own crawlers scrape the web continuously. Worth knowing: most providers now run separate bots for training versus search, and you can allow one without the other. OpenAI uses GPTBot for training and OAI-SearchBot for its search product (ChatGPT search). Anthropic uses ClaudeBot for training and Claude-SearchBot / Claude-User for search and user-initiated fetches. Perplexity uses PerplexityBot and Perplexity-User. If your goal is to be cited rather than to be trained on, the search-oriented bots are the ones that matter most, so keep them allowed.

Retrieval-Augmented Generation (RAG) means that when someone asks a question, the AI retrieves relevant documents from its index and uses them to generate an answer with citations. Your content has to be in the index first.

Real-time search (ChatGPT's web search, Perplexity's default behavior) re-crawls live pages at query time, parsing the structured content it finds.

In all three cases, the AI needs to:

  • Get access to your content: crawler permissions
  • Find your content: discovery mechanisms
  • Parse and understand it: structure and schema
  • Trust it: entity signals and expertise indicators

Most GEO advice focuses entirely on that last point. The first three are where the technical work lives.


GEO vs AEO: what's the difference and why does it matter technically?

These two terms get used interchangeably, but they describe different goals, and the distinction shapes which technical elements you prioritize.

GEO (Generative Engine Optimization) is about being cited or referenced in AI-generated content. ChatGPT writes a summary of a topic and links to your post. Google AI Overviews reference your page as a source. Claude recommends your content when someone asks for resources on a subject. The AI is generating something, and you want to appear in it.

AEO (Answer Engine Optimization) is about being the answer. Someone asks a question and the AI (or Google's featured snippet, or a voice assistant) reads out your content as the direct response. AEO has older roots in featured snippets and voice search, but now maps directly onto how AI chatbots handle factual questions.

GEO is the broader category. AEO is a subset of it. If you're building a GEO-ready site, you're covering AEO along the way. But the technical emphasis differs.

Technical setup that primarily supports AEO:

  • FAQ schema: the clearest signal that your content is structured as a direct question-and-answer pair
  • HowTo schema: for step-by-step processes an AI can extract and present as instructions
  • Direct answers near the top of each page: the first paragraph should be answerable, not a preamble
  • Question-format headings: "How does X work?" rather than "X overview"

Technical setup that primarily supports GEO:

  • llms.txt and llms-full.txt: designed specifically for LLM context, not traditional search engines
  • robots.txt AI crawler allowlist: getting LLM-specific crawlers into your content in the first place
  • Person/Organization schema with sameAs: entity establishment so AI systems can confidently attribute content to you across platforms
  • knowsAbout in your Person schema: maps your identity to topic areas AI systems use when generating responses

Technical setup that supports both:

  • Sitemap and IndexNow: fast discovery helps both traditional search and AI indexing
  • BlogPosting schema with dateModified: freshness signals matter for citation ranking and answer confidence
  • Canonical URLs: clean attribution for both GEO sourcing and AEO answer credit
  • Open Graph and meta tags: surface-level parsability that all systems benefit from

The practical takeaway: if your goal is to show up in AI chatbot answers to specific questions (AEO), prioritize structured content and FAQ/HowTo schema. If your goal is to build brand presence in AI-generated outputs broadly (GEO), the entity layer (llms.txt, Person schema, sameAs) does the heavy lifting. Most sites benefit from building both.


1. robots.txt: explicitly invite AI crawlers in

This is the most underrated change you can make, and the fastest to implement.

By default, a User-agent: * / Allow: / in your robots.txt technically includes AI bots. But explicitly naming them sends an active, intentional signal. More practically: as crawler policies evolve and platform defaults shift, explicit allowances give you clear documentation of your intent.

Here's exactly what my robots.txt looks like:

# All crawlers: full access, except private pages.
User-agent: *
Allow: /
Disallow: /dashboard
Disallow: /live

# AI / LLM crawlers — same policy, named so intent is explicit. Grouped on
# purpose: a robot obeys only its single most-specific group, so the Disallow
# rules must be repeated here, not inherited from User-agent: *.
User-agent: GPTBot
User-agent: OAI-SearchBot
User-agent: ChatGPT-User
User-agent: ClaudeBot
User-agent: Claude-SearchBot
User-agent: Claude-User
User-agent: PerplexityBot
User-agent: Perplexity-User
User-agent: Google-Extended
User-agent: Applebot-Extended
User-agent: CCBot
User-agent: cohere-ai
User-agent: Meta-ExternalAgent
Allow: /
Disallow: /dashboard
Disallow: /live

Sitemap: https://www.gigikenneth.com/sitemap-index.xml

One gotcha worth calling out (I got this wrong at first): a crawler obeys only the single most specific user-agent group that matches it, and does not merge rules from the User-agent: * group (Google's robots.txt spec). So if you name GPTBot in its own group with just Allow: /, it will not inherit the Disallow: /dashboard from the wildcard group. Either repeat your disallows inside each named group (as above, using one shared group), or skip the named groups entirely and rely on User-agent: * — but don't assume inheritance.

Why bother naming them at all: the User-agent: * / Allow: / default already permits AI bots, so naming them is optional. It's a documentation signal of intent, not a functional requirement. If you'd rather keep robots.txt minimal, a single permissive wildcard group with your disallows is perfectly sufficient.

The user-agents to know, as of mid-2026 (verify against each provider's current docs, since these change):

PlatformBot user-agentsNotes
OpenAIGPTBot (training), OAI-SearchBot (search), ChatGPT-User (user fetch)Allow OAI-SearchBot to be surfaced in ChatGPT search
AnthropicClaudeBot (training), Claude-SearchBot, Claude-UserNames updated in 2025; older Claude-Web / anthropic-ai are being phased out
PerplexityPerplexityBot, Perplexity-User
GoogleGoogle-ExtendedTraining/grounding opt-out only — it does not control whether you appear in Google AI Overviews or AI Mode
AppleApplebot-Extended
Common CrawlCCBotFeeds many LLM datasets
Cohere / Metacohere-ai, Meta-ExternalAgent

The Sitemap: line at the bottom points crawlers to your sitemap; it's a cheap, useful signal to include.

(For context, many major publishers — the New York Times, The Guardian, and others — deliberately block AI crawlers to protect content from uncompensated training. That's a valid choice. This post assumes the opposite goal: you want to be found and cited.)


2. Sitemap: curate, don't just dump

A sitemap should be a curated list of pages you want indexed, not every URL that exists on your domain.

On this site, the auto-generated sitemap excludes:

  • Draft posts: unpublished work shouldn't appear in AI answers
  • Reposts: content I've published on Medium or Substack and canonicalized back to the original source; duplicate content with a canonical pointing elsewhere doesn't belong in the sitemap
  • Private pages: the /dashboard is gated and irrelevant to crawlers
  • Work pending sign-off: case studies waiting for client approval

The rule: if a page is noindex, has a canonical pointing elsewhere, or is private, it should be out of the sitemap. Feeding crawlers noise dilutes the signal from the pages you want cited.

On WordPress, Yoast and Rank Math handle this logic when you mark pages as noindex. On custom stacks, it's worth auditing what your sitemap includes. Most developers just generate from all routes and don't think about filtering.


3. IndexNow: stop waiting for crawlers to find you

Standard crawl scheduling means a new post might sit unindexed for days or weeks before AI systems see it. IndexNow changes that.

IndexNow is an open protocol supported by Bing, Yandex, and any search engine using Bing's index (which includes ChatGPT Search). When you publish or update content, you push a notification to the IndexNow API and participating engines immediately queue those URLs for crawling. No waiting for the next scheduled crawl.

Why this matters for AI visibility: ChatGPT's search feature has historically drawn on Bing's index, and other AI search tools lean on Bing/IndexNow-participating engines too. Faster indexing there plausibly means faster availability to those AI search surfaces, though the exact pipelines are proprietary and shift over time. Either way, getting indexed in hours instead of weeks is a clear win for traditional and AI search alike.

Setup is three steps:

  1. Generate an IndexNow key (a random string like a UUID)
  2. Host a text file at yourdomain.com/<your-key>.txt containing just the key value
  3. After every publish, POST your new/updated URLs to https://api.indexnow.org/indexnow

On my site this is automated in the build: after every production deploy, a script reads the sitemap and submits the URLs to IndexNow. One caveat worth being honest about: IndexNow's guidance is that you should submit only URLs that were recently added, changed, moved, or deleted, not your whole sitemap every time. Resubmitting the full set on a small archive is a pragmatic simplification (participating engines ignore unchanged URLs), but the cleaner approach, and the right one as a site grows, is to diff against the previous deploy and submit only what changed. If the ping fails, the build still succeeds; IndexNow is a best-effort notification, not a dependency.

WordPress users: the IndexNow plugin handles this in one click. Webflow: third-party integrations exist. Custom stack: about 20 lines of code.

Also verify in Bing Webmaster Tools. Bing's panel gives you IndexNow submission logs and crawl status. Given how much AI search tooling touches the Bing/IndexNow ecosystem, it's a useful place to confirm your new posts are actually being picked up.


4. llms.txt: the index file AI was missing

This is the one I find most interesting because it's new, it's growing, and almost no websites have it yet.

llms.txt is a plain-text file served at /llms.txt on your domain. It follows an emerging standard (llmstxt.org) and is a structured, human-readable summary of your site designed specifically for LLMs: a cover letter for AI systems, not for human visitors.

Here's the format for mine:

# Gigi Kenneth

> AI content marketer, product storyteller, and founder of Asele. Practical writing
> on AI, content marketing, content strategy, femtech, and building in public.

Gigi Kenneth (also Gift Kenneth) helps AI, data, and life-sciences teams turn
technical work into clear content that drives understanding, trust, and decisions.
She is the founder of Asele, a women's health platform built for African women.

## Key pages
- [About](https://www.gigikenneth.com/about): Background, expertise, and what she does.
- [Services](https://www.gigikenneth.com/services): Content strategy and writing services.
- [Work & case studies](https://www.gigikenneth.com/work): Selected projects.
- [Talks](https://www.gigikenneth.com/talks): Speaking, panels, and features.
- [Blog](https://www.gigikenneth.com/blog): Full writing archive.

## Writing
- [Article title](https://www.gigikenneth.com/post/slug): One-sentence excerpt.
- ...

## Contact
- Email: hello@gigikenneth.com
- LinkedIn: https://www.linkedin.com/in/gigikenneth/

Instead of an AI crawling 60+ pages and piecing together who you are, you hand it a map. It's the difference between sending someone into a library with no card catalog and handing them an annotated reading list.

The key is keeping it current. Mine is dynamically generated at build time from the live posts collection. Every time I publish something new, the llms.txt updates automatically. No manual maintenance, no going stale.

The format is intentionally simple, parseable by any AI without special tooling.


5. llms-full.txt: the deep context version

One level deeper: /llms-full.txt is a companion file containing the full body text of every published post, separated by --- dividers with metadata headers (title, URL, published date, category).

The purpose is straightforward. When an AI system wants to deeply understand a site's content (for research, summarization, understanding depth of expertise), instead of making 60+ HTTP requests and parsing HTML each time, it can fetch one file and get the complete picture.

For a site with a substantial archive, this is a meaningful reduction in crawl friction. And clean plain text is easier for AI to process than HTML with navigation, footers, sidebars, and ad containers cluttering the signal.

Not every site needs this. If you have fewer than 20 posts, it's nice-to-have. If you have a deep archive, it's worth setting up.


6. JSON-LD schema: establish your entity

Schema markup is the part of the GEO conversation that does get mentioned, but usually in a shallow "just add FAQ schema" framing. The deeper purpose is entity establishment.

AI systems need to understand not just what your pages say, but who you are. Is the "Gigi Kenneth" on this website the same person mentioned on LinkedIn? The same person who gave that talk? The founder of Asele? Entity disambiguation is a core challenge for AI systems, and JSON-LD structured data is how you help them solve it: a machine-readable format that doesn't depend on inference.

On the homepage, I have a Person schema node with a stable @id anchor:

{
  "@type": "Person",
  "@id": "https://www.gigikenneth.com/#person",
  "name": "Gigi Kenneth",
  "alternateName": "Gift Kenneth",
  "url": "https://www.gigikenneth.com",
  "jobTitle": "AI Content Marketer & Product Storyteller",
  "worksFor": {
    "@type": "Organization",
    "name": "Asele",
    "url": "https://aseleapp.com"
  },
  "knowsAbout": [
    "AI content marketing",
    "Generative engine optimization",
    "Content strategy",
    "Technical writing",
    "Femtech",
    "Women's health technology"
  ],
  "sameAs": [
    "https://www.linkedin.com/in/gigikenneth/",
    "https://github.com/gigikenneth",
    "https://medium.com/@gigikenneth"
  ]
}

Three things here are worth calling out:

@id anchors. The @id value is a stable identifier. Every other schema node on the site that references me (individual blog posts, the FAQ page, the WebSite node) references this anchor instead of duplicating the full person data. The result is a coherent knowledge graph where all pieces connect back to a single authoritative entity definition.

sameAs array. This tells AI systems (and search engines) that the same entity exists at these external URLs. It's how Google and others link your website to your LinkedIn profile, Medium publications, and other online presences. Without this, each platform where you appear looks like a separate entity that might or might not be the same person.

knowsAbout array. Explicitly declaring areas of expertise gives systems a direct, structured statement of your topics rather than making them infer it from your content. Whether it measurably changes how often you're matched to queries isn't something anyone can prove publicly, but it's a clean, low-cost signal to provide.

There's also a WebSite schema node that references the #person anchor as publisher, establishing the formal relationship between the site and who runs it.


7. JSON-LD for content: BlogPosting and FAQPage

Every blog post on this site has a BlogPosting schema embedded in the page:

{
  "@type": "BlogPosting",
  "@id": "https://www.gigikenneth.com/post/slug#article",
  "headline": "Article title",
  "description": "Meta description",
  "datePublished": "2026-01-15T00:00:00.000Z",
  "dateModified": "2026-07-20T00:00:00.000Z",
  "author": { "@id": "https://www.gigikenneth.com/#person" },
  "publisher": { "@id": "https://www.gigikenneth.com/#person" },
  "articleSection": "Content",
  "keywords": ["content marketing", "AI search", "GEO"],
  "inLanguage": "en"
}

The author and publisher fields reference the #person anchor from the homepage, not a standalone object. This attribution chain is how AI systems confirm that this article was written by the same entity they already know about.

A note on FAQ schema: Since 2023, Google stopped rendering FAQ rich results for most non-health and non-government sites. It's still low-cost to implement, and the plausible argument for keeping it is that FAQ-structured data unambiguously marks a block of text as a direct question-and-answer pair, which may make it easier for systems to lift as an answer. To be clear, that citation benefit isn't publicly established, and Google has said its AI features don't require special schema; treat FAQ markup as a cheap, sensible clarity signal rather than a proven citation lever.

My Services page has FAQ schema with six question-answer pairs covering common questions about working with me. The questions are written the same way someone would phrase them to an AI: naturally, as complete sentences, with direct answers.

BreadcrumbList on every blog post shows the navigation structure: Home → Blog → Post title. This helps AI systems understand where a piece of content sits within the site hierarchy.


8. Canonical URLs: clean attribution signals

When the same content exists at multiple URLs, or when you cross-post between your site, Medium, Substack, and LinkedIn Articles, canonical tags tell search engines and AI systems which version is authoritative.

On this site:

  • Original posts have a canonical pointing to their URL on this domain
  • Posts that originated elsewhere (newsletters imported from Substack, pieces first published on another platform) have the canonical pointing to the original source
  • Those reposts are also excluded from the sitemap, so crawlers don't index the duplicate version

Why this matters for AI: without canonical signals, an AI might cite the same content in multiple contexts with different URLs, diluting attribution. Clear canonicals mean there's a clean chain from the content back to you as the original source, even when your work is distributed across platforms.


9. Meta tags: the basics that still matter

Open Graph and Twitter Card tags aren't glamorous, but they're standard metadata that many systems read first when generating a preview, summary, or card for a page. It's reasonable to expect some AI parsers lean on og:title and og:description the same way social platforms do, though this is convention rather than a documented AI-citation factor. Either way, they're table stakes you'd want for social sharing regardless.

Minimum viable meta setup per page:

<meta name="description" content="Specific, accurate description of this page">
<meta property="og:title" content="Page title">
<meta property="og:description" content="Same or similar to description">
<meta property="og:type" content="article">  <!-- "website" for non-posts -->
<meta property="og:url" content="https://yourdomain.com/post/slug">
<meta name="twitter:card" content="summary_large_image">

The og:type: article vs website distinction is meaningful: it signals to parsers that this is a time-stamped piece of content, not a static landing page, which affects how it's treated in freshness-weighted retrieval.

The noindex signal matters too: any page you don't want in AI answers (drafts, admin pages, private content, thin pages) should have <meta name="robots" content="noindex, follow">. Follow is fine; you just want to exclude the page from indexing.


10. Freshness signals: dateModified is underrated

Freshness is a long-standing ranking factor in traditional search, and it's reasonable to expect it carries weight for AI systems ranking sources by relevance too, though the latter isn't publicly documented. An article published in 2022 with no dateModified signal can look stale even if you updated it in 2025 with current statistics. Populating dateModified costs nothing and removes that ambiguity.

Every blog post on this site has both datePublished and dateModified fields in the BlogPosting schema. The dateModified value comes from an updatedAt field in the post frontmatter. When I revisit an older post to update statistics, add new sections, or correct outdated information, I update that field. The freshness signal flows through to the schema automatically.

This is a simple but high-leverage habit: if you have older posts that still get traffic and cover topics where AI citations would benefit you, revisiting them with a content refresh and an updated dateModified is one of the faster wins in the GEO stack.

On WordPress, updating a post automatically updates the dateModified in your schema (if your SEO plugin is wired correctly). On custom stacks, make sure you have a field for this and that it's populating the schema.


Monitoring: how to know if it's working

You can't optimize what you can't measure. The tools I use:

AI citation tracking:

  • Profound: tracks when and how AI systems mention your brand or content in responses
  • Otterly.AI: monitors AI search visibility across platforms
  • Peec AI: competitive AI visibility benchmarking
  • Ahrefs Brand Radar: tracks AI-generated responses mentioning your brand across platforms

Traditional SEO as a baseline:

  • Google Search Console: clicks, impressions, average position. I have a private dashboard built directly into this site that pulls GSC data via the Search Console API; monitoring from within the site rather than bouncing to another tool helps me stay consistent about checking it.
  • IndexNow logs + Bing Webmaster Tools: to confirm new posts are being picked up

Set a cadence. Monthly is enough for most people: check citation coverage, see which pages are being cited (to understand what patterns work), and identify gaps where you have strong content that isn't being picked up. If you want to tie this back to business outcomes rather than vanity metrics, I break that down in how to measure ROI in technical content marketing.


The complete checklist

0 of 0

Access

  • [ ] robots.txt explicitly allows AI crawler user-agents (GPTBot, ClaudeBot, PerplexityBot, Google-Extended, and the rest)
  • [ ] No critical content locked behind JavaScript that crawlers can't render
  • [ ] Private/admin pages are noindex, nofollow or disallowed in robots.txt
  • [ ] The Sitemap: directive appears at the bottom of robots.txt

Discovery

  • [ ] XML sitemap exists and excludes drafts, noindex pages, and reposts with external canonicals
  • [ ] IndexNow key file is live at yourdomain.com/<key>.txt
  • [ ] IndexNow pings are sent on publish and update
  • [ ] Bing Webmaster Tools is connected (Bing powers ChatGPT Search)

AI context

  • [ ] /llms.txt is live: structured overview with key pages and all posts
  • [ ] /llms-full.txt is live (valuable for sites with 20+ posts)

Identity

  • [ ] Person or Organization JSON-LD on homepage with a stable @id anchor
  • [ ] sameAs array linking to social profiles, external publications, and other platforms
  • [ ] knowsAbout array declaring areas of expertise
  • [ ] WebSite JSON-LD referencing the person/org as publisher

Content schema

  • [ ] BlogPosting JSON-LD on every article (author, publisher, datePublished, dateModified, keywords, all referencing the identity @id)
  • [ ] BreadcrumbList on blog posts
  • [ ] FAQPage JSON-LD on any page that answers questions (still valuable for AI citation even after Google's visual deprecation)

Meta and canonicals

  • [ ] <link rel="canonical"> on every page, pointing to the correct authoritative URL
  • [ ] Reposts and cross-posts canonicalized to the original source
  • [ ] Open Graph tags on all pages
  • [ ] noindex set on pages you don't want in AI answers

Freshness

  • [ ] dateModified in BlogPosting schema, populated from an actual updatedAt field
  • [ ] High-value older posts refreshed with current content and updated updatedAt

Monitoring

  • [ ] Google Search Console connected and checked on a schedule
  • [ ] At least one AI citation monitoring tool in use

Most of this translates to any platform. You don't need a custom-built site. You need to understand what signals matter and make sure your platform is sending them correctly.

The marketers who will do well in AI search aren't just the ones with the best content. They're the ones who've done the plumbing work underneath it. The good news is that most of this is a one-time setup. Build it properly once, keep the content layer current, and the infrastructure does its job quietly in the background.

If you've already done some of this and want to go deeper on the content strategy side, my post on how AI Overviews are rewriting the rules of marketing covers the higher-level shifts, and how content marketers can nail LLM optimization gets into the writing side of getting cited. For the workflow side, there's a separate walkthrough of the AirOps AEO tracking workflow I built for Asele on top of all this. And if you're still shoring up the fundamentals, how much SEO you really need for technical content marketing is the groundwork underneath the GEO layer.

On this page