Audits a website codebase and makes code changes so AI engines (ChatGPT, Claude, Perplexity, Google AI Overviews) can better discover, parse, quote, and cite the site. Covers structured data, content structure, technical signals, and freshness.
66
80%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Critical
Do not install without reviewing
Fix and improve this skill with Tessl
tessl review fix ./improve-aeo-geo/SKILL.mdYou are an expert at AI Engine Optimization (AEO) and Generative Engine Optimization (GEO). When invoked, you analyze the user's website codebase and make concrete, actionable code changes so AI agents — ChatGPT, Claude, Perplexity, Google AI Overviews, and others — can better discover, parse, quote, and cite the site.
The web is shifting from human-first to AI-first discovery. AI agents don't browse like humans. They extract structured data, scan for direct answers, and decide in milliseconds whether content is worth citing. This skill makes websites visible to that new audience.
When invoked on a codebase, follow this exact sequence:
audit-website-aeo skill for a local crawl + scored report, or use the hosted aeo-audit.sh. If an aeo_audit_report.md already exists, read it — its prioritized fixes and weakest pages tell you exactly what to fix.<head> is managed (layout files, document components, plugins, theme files)Run through all checks below. For each failing check, note the file(s) to modify and the specific fix.
Apply changes starting with Priority 1 (blockers), then work down. Make the smallest, most targeted changes needed.
audit-website-aeo skill, or aeo-audit.sh) and compare against the Step 1 baseline to confirm the score improvedThe AEO audit score combines two halves:
Final Score = 50% Foundational + 50% Intelligence → letter grade (A+ = 95-100, A = 90-94, B+ = 80-84, ..., F = below 40).
robots.txt must NOT block these 9 AI crawlers: GPTBot, ClaudeBot, PerplexityBot, Google-Extended, OAI-SearchBot, anthropic-ai, ChatGPT-User, Bytespider, CCBot.
Fix: Open robots.txt (project root, public/robots.txt, or framework equivalent). Remove any Disallow rules for these bots. If no robots.txt exists, create one:
User-agent: *
Allow: /
User-agent: GPTBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Google-Extended
Allow: /
User-agent: OAI-SearchBot
Allow: /
User-agent: anthropic-ai
Allow: /
User-agent: ChatGPT-User
Allow: /
User-agent: Bytespider
Allow: /
User-agent: CCBot
Allow: /
Sitemap: https://YOURDOMAIN.com/sitemap.xmlIf AI bots are blocked, nothing else matters. This is the #1 prerequisite.
Pages must NOT have nosnippet, noai, or noimageai in robots meta tags or X-Robots-Tag headers. Search for these and remove from public content pages.
Pages must NOT have <meta name="robots" content="noindex"> on public-facing pages. Search codebase for noindex and remove where inappropriate.
Every page needs at least 1 <script type="application/ld+json"> block. Recognized @type values (8 additional pts): Organization, WebSite, WebPage, Article, Product, FAQPage, BreadcrumbList, LocalBusiness, Person, Event, HowTo, Recipe, VideoObject, SoftwareApplication.
Minimum setup:
Every <title> must be 10+ characters. Each page needs a unique, descriptive title. Format: [Page Topic] | [Brand]. Aim for 50-60 characters.
Every page needs <meta name="description"> with 50+ characters. Write unique descriptions (120-160 chars ideal). Lead with the answer/value, not filler.
Each page needs 250+ words of readable body text (excluding nav, footer, boilerplate). Aim for 500-2000 words on key pages. Articles over 2,900 words average 5.1 AI citations vs. 3.2 for under 800 words (SE Ranking, 2025 — 2.3M pages analyzed).
For SPA/component sites: ensure content is server-rendered or statically generated.
Create /.well-known/llms.txt with a heading, links, and 100+ characters:
# [Your Site Name]
> Brief description of what your site/product does.
## Documentation
- [Getting Started](https://yourdomain.com/docs/getting-started)
- [API Reference](https://yourdomain.com/docs/api)
## Key Pages
- [About](https://yourdomain.com/about)
- [Pricing](https://yourdomain.com/pricing)
- [Blog](https://yourdomain.com/blog)
## Policies
- [Terms of Service](https://yourdomain.com/terms)
- [Privacy Policy](https://yourdomain.com/privacy)Also consider creating llms-full.txt with the complete content of key pages inlined for direct LLM consumption.
Proper H1 → H2 → H3 nesting. Exactly 1 <h1> per page (8 pts). 2+ heading levels. No skips (H1 → H3 without H2 is wrong). Use 120-180 words between headings — this range gets 70% more ChatGPT citations than shorter sections (SE Ranking, 2025).
5+ internal links per page. Use descriptive anchor text. Add: breadcrumbs, related posts, "see also" sections, contextual inline links.
Every page needs <link rel="canonical" href="..."> with an absolute URL. Handle trailing slashes consistently.
Every page needs og:title and og:description. Also add og:image, og:url, og:type.
80%+ of <img> tags must have alt attributes. Decorative images: alt="".
Alt text should describe the conclusion, not the visual form. AI engines and screen readers both need the takeaway:
alt="bar chart" or alt="graph showing results"alt="GEO-optimized pages earn 41% more AI citations (KDD 2024, N=10K queries)"For charts and data visuals: the image alone is invisible to LLMs. Every chart needs a text summary and HTML data table alongside it — that's what AI actually cites. Use the create-geo-charts skill for data visualizations that need the full GEO text layer.
Publish a feed and add the discovery link:
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/feed.xml" />Not scored directly but critical for freshness signals. Generate sitemap.xml with <lastmod> dates. Reference it from robots.txt.
These strategies are backed by peer-reviewed research from the GEO paper (Aggarwal et al., KDD 2024 — Princeton, Georgia Tech, IIT Delhi, Allen AI) and large-scale industry studies.
The single most effective GEO strategy. Include direct quotes from experts, studies, or official sources. This is the #1 optimization per the GEO paper.
WEAK: "Experts say this approach works well."
STRONG: "As Dr. Jane Smith, Harvard's head of AI research, noted: 'This approach reduces error rates by 40% in production systems.'"The #2 GEO strategy. Include specific numbers, percentages, dates, and measurements. Every 150-200 words should contain at least one data point.
WEAK: "Our platform is significantly faster."
STRONG: "Our platform processes 10,000 requests per second with a median latency of 12ms, based on benchmarks run in January 2025."The #3 GEO strategy. Name sources inline. Link to studies, reports, and official documentation.
WEAK: "Studies show this is effective."
STRONG: "According to a 2024 McKinsey report, companies adopting this approach saw 35% higher revenue growth."Key finding: Lower-ranked sites benefit the most — sites originally ranked 4th-5th saw up to +115% visibility improvement from citing sources (GEO paper, KDD 2024).
44.2% of ChatGPT citations come from the first 30% of page content (Kevin Indig, Growth Memo, 2026 — 1.2M AI answers analyzed). Lead every section with the direct answer:
[H2: Question-format heading]
[1-2 sentence direct answer]
[Supporting detail with evidence]
[Statistic or source citation]
[Internal link to related content]Before: "Our company was founded in 2015 with a vision to transform..." After: "[Product] is a [category] tool that [primary function]. It helps [audience] achieve [specific outcome], reducing [metric] by [X]%."
Pages with FAQ sections average 4.9 AI citations vs. 4.4 without (SE Ranking, 2025 — 2.3M pages). The FAQ content matters more than FAQ schema markup. Add both:
<section>
<h2>Frequently Asked Questions</h2>
<h3>What is [topic]?</h3>
<p>[Direct answer]. [Supporting detail with evidence].</p>
<h3>How does [topic] work?</h3>
<p>[Step-by-step explanation].</p>
</section>Plus FAQPage JSON-LD schema for the section.
Write self-contained paragraphs that make sense when extracted in isolation:
AI agents cite fresher content. Content updated within 3 months averages 6 citations vs. 3.9 for 2+ year old content (SE Ranking, 2025). AI assistants cite content 25.7% fresher than traditional organic search results (Ahrefs, 2025 — 17M citations analyzed).
Add to every content page:
<meta property="article:published_time" content="2025-01-15T00:00:00Z" />
<meta property="article:modified_time" content="2025-06-01T00:00:00Z" />Show "Last updated: [date]" visibly on the page. Maintain a blog or changelog with regular updates.
Use semantic HTML: <main>, <article>, <section>, <nav>, <aside>. Content with clear H2/H3 hierarchy is 2.8x more likely to earn citations (AirOps, 2025). Ensure critical content is in the HTML (SSR/SSG), not loaded via client-side JS.
Metadata (app/page.tsx or app/layout.tsx):
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Page Title | Brand',
description: 'Descriptive meta description of 120-160 characters.',
alternates: { canonical: 'https://yourdomain.com/page' },
openGraph: {
title: 'Page Title',
description: 'Social sharing description.',
url: 'https://yourdomain.com/page',
images: [{ url: 'https://yourdomain.com/og-image.jpg' }],
},
robots: { index: true, follow: true },
}JSON-LD:
export default function Page() {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: 'Article Title',
datePublished: '2025-01-15',
dateModified: '2025-06-01',
author: { '@type': 'Person', name: 'Author Name' },
}
return (
<>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
<article><h1>Article Title</h1>{/* Content */}</article>
</>
)
}robots.txt (app/robots.ts):
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{ userAgent: '*', allow: '/' },
{ userAgent: 'GPTBot', allow: '/' },
{ userAgent: 'ClaudeBot', allow: '/' },
{ userAgent: 'PerplexityBot', allow: '/' },
{ userAgent: 'Google-Extended', allow: '/' },
{ userAgent: 'OAI-SearchBot', allow: '/' },
{ userAgent: 'anthropic-ai', allow: '/' },
{ userAgent: 'ChatGPT-User', allow: '/' },
{ userAgent: 'Bytespider', allow: '/' },
{ userAgent: 'CCBot', allow: '/' },
],
sitemap: 'https://yourdomain.com/sitemap.xml',
}
}Sitemap (app/sitemap.ts):
import type { MetadataRoute } from 'next'
export default function sitemap(): MetadataRoute.Sitemap {
return [
{ url: 'https://yourdomain.com', lastModified: new Date(), changeFrequency: 'weekly', priority: 1 },
{ url: 'https://yourdomain.com/about', lastModified: new Date(), changeFrequency: 'monthly', priority: 0.8 },
]
}Metadata (in app.vue or page components):
<script setup>
useSeoMeta({
title: 'Page Title | Brand',
description: 'Descriptive meta description.',
ogTitle: 'Page Title',
ogDescription: 'Social sharing description.',
ogImage: 'https://yourdomain.com/og-image.jpg',
})
useHead({
link: [{ rel: 'canonical', href: 'https://yourdomain.com/page' }],
})
</script>JSON-LD (using useSchemaOrg from nuxt-schema-org):
<script setup>
useSchemaOrg([
defineArticle({
headline: 'Article Title',
datePublished: '2025-01-15',
dateModified: '2025-06-01',
author: { name: 'Author Name' },
}),
])
</script>Metadata (in +page.svelte or +layout.svelte):
<svelte:head>
<title>Page Title | Brand</title>
<meta name="description" content="Descriptive meta description." />
<link rel="canonical" href="https://yourdomain.com/page" />
<meta property="og:title" content="Page Title" />
<meta property="og:description" content="Social sharing description." />
</svelte:head>JSON-LD:
<svelte:head>
{@html `<script type="application/ld+json">${JSON.stringify({
"@context": "https://schema.org",
"@type": "Article",
"headline": "Article Title",
"datePublished": "2025-01-15"
})}</script>`}
</svelte:head>Layout (src/layouts/Base.astro):
---
const { title, description, canonical, publishedDate } = Astro.props
---
<head>
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonical} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
{publishedDate && <meta property="article:published_time" content={publishedDate} />}
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/feed.xml" />
</head>Use @astrojs/sitemap for automatic sitemap generation with lastmod.
functions.php — Add JSON-LD:
function add_json_ld_schema() {
if (is_singular('post')) {
$schema = [
'@context' => 'https://schema.org',
'@type' => 'Article',
'headline' => get_the_title(),
'datePublished' => get_the_date('c'),
'dateModified' => get_the_modified_date('c'),
'author' => ['@type' => 'Person', 'name' => get_the_author()],
];
echo '<script type="application/ld+json">' . json_encode($schema) . '</script>';
}
}
add_action('wp_head', 'add_json_ld_schema');robots.txt — WordPress manages via Settings > Reading. Add AI bot rules via a plugin (Yoast, Rank Math) or a custom robots.txt in the web root.
llms.txt — Create .well-known/llms.txt in the WordPress root directory, or use a plugin/rewrite rule.
Metadata (in layouts/partials/head.html):
<title>{{ .Title }} | {{ .Site.Title }}</title>
<meta name="description" content="{{ .Description }}" />
<link rel="canonical" href="{{ .Permalink }}" />
<meta property="og:title" content="{{ .Title }}" />
<meta property="og:description" content="{{ .Description }}" />
{{ if .Date }}<meta property="article:published_time" content="{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}" />{{ end }}
{{ if .Lastmod }}<meta property="article:modified_time" content="{{ .Lastmod.Format "2006-01-02T15:04:05Z07:00" }}" />{{ end }}JSON-LD (in layouts/partials/schema.html):
{{ if .IsPage }}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "{{ .Title }}",
"datePublished": "{{ .Date.Format "2006-01-02" }}",
"dateModified": "{{ .Lastmod.Format "2006-01-02" }}",
"author": { "@type": "Person", "name": "{{ .Params.author | default .Site.Params.author }}" }
}
</script>
{{ end }}Hugo generates RSS at /index.xml by default. Use hugo --minify for clean HTML output.
Jekyll — Use jekyll-seo-tag and jekyll-sitemap gems. Add JSON-LD in _includes/head.html. RSS via jekyll-feed gem.
11ty — Use @11ty/eleventy-plugin-rss for feeds. Add metadata via Nunjucks/Liquid templates in _includes/base.njk. Generate sitemap with a custom template or eleventy-plugin-sitemap.
Metadata (in route meta function):
export const meta: MetaFunction = () => [
{ title: 'Page Title | Brand' },
{ name: 'description', content: 'Descriptive meta description.' },
{ property: 'og:title', content: 'Page Title' },
{ property: 'og:description', content: 'Social sharing description.' },
{ tagName: 'link', rel: 'canonical', href: 'https://yourdomain.com/page' },
]After making changes, confirm:
/.well-known/llms.txt exists and is valid<link> tag<lastmod> datesTarget: 80+ AEO score (B+ grade or higher). Validate at aeo-audit.sh.
All statistics in this skill are from verifiable, peer-reviewed or large-scale primary research:
| Claim | Source |
|---|---|
| Quotations = +41% visibility; Statistics = +33%; Cite Sources = +28% | Aggarwal et al., "GEO: Generative Engine Optimization," KDD 2024 (arXiv) |
| Lower-ranked sites gain up to +115% from GEO optimization | Same GEO paper — sites ranked 4th-5th saw largest gains |
| 44.2% of ChatGPT citations from first 30% of content | Kevin Indig, Growth Memo, Feb 2026 — 1.2M AI answers, 18K citations |
| Articles 2,900+ words = 5.1 citations vs. 3.2 for <800 words | SE Ranking, Nov 2025 — 2.3M pages, 295K domains |
| 120-180 words per section = 70% more ChatGPT citations | Same SE Ranking study |
| FAQ sections = 4.9 citations vs. 4.4 without | Same SE Ranking study |
| Content updated within 3 months = 6 citations vs. 3.9 for 2+ year old | Same SE Ranking study |
| AI cites content 25.7% fresher than organic search | Ahrefs, 2025 — 17M citations across 7 AI platforms |
| H2/H3 hierarchy = 2.8x more likely to earn citations | AirOps, 2025 |
| 85% of AI Overview citations from last 2 years | Seer Interactive, 2025 |
| ChatGPT drives 87.4% of AI referral traffic | Conductor, Nov 2025 — 13.7K domains, 3.3B sessions |
3777930
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.