# aeo.js — Answer Engine Optimization for the Modern Web - Complete Documentation This file contains all documentation concatenated into a single file for easy consumption by LLMs. > Make your website discoverable by ChatGPT, Claude, Perplexity & AI search engines. Auto-generates llms.txt, robots.txt, sitemap, JSON-LD structured data & more. ## Table of Contents This document includes all content from this project. Each section is separated by a horizontal rule (---) for easy parsing. --- # Contributors URL: https://aeojs.org/contributors > The people who make aeo.js possible. ## Contributors 6 contributors have shaped aeo.js. Thank you. - [rubenmarcus 77 commits](https://github.com/rubenmarcus) - [KimHyeongRae0 4 commits](https://github.com/KimHyeongRae0) - [FabioRocha231 3 commits](https://github.com/FabioRocha231) - [ribeiroevandro 2 commits](https://github.com/ribeiroevandro) - [HusseinAdeiza 1 commit](https://github.com/HusseinAdeiza) - [mhanelia 1 commit](https://github.com/mhanelia) Want to join them? [Open a PR](https://github.com/multivmlabs/aeo.js) . Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Audit & Citability URL: https://aeojs.org/features/audit > Audit your AEO setup and measure your site ## Audit & Citability ## Site Audit [Section titled “Site Audit”](#site-audit) The auditSite function checks your site for AEO best practices and returns a detailed report: - import { auditSite, formatAuditReport, getGrade, resolveConfig } from 'aeo.js'; const config = resolveConfig({ title: 'My Site', url: 'https://mysite.com', pages: [{ pathname: '/', title: 'Home', content: 'Welcome to my site.' }], }); const result = auditSite(config); console.log(formatAuditReport(result)); console.log('Grade:', getGrade(result.score)); The audit checks for: Presence of robots.txt, llms.txt, llms-full.txt - Sitemap accessibility - Structured data (JSON-LD) - Open Graph meta tags - AI crawler accessibility You can also run it from the CLI: Terminal window npx aeo.js check ## Citability Score [Section titled “Citability Score”](#citability-score) Measure how likely AI engines are to cite your content: import { formatPageCitability, resolveConfig, scorePageCitability, scoreSiteCitability } from 'aeo.js'; // Score a single page const pageScore = scorePageCitability({ pathname: '/', title: 'Home', content: '# Home\n\nMy site publishes practical guides for AI-ready content.', }); console.log(formatPageCitability(pageScore)); // Score the whole site const config = resolveConfig({ title: 'My Site', url: 'https://mysite.com', pages: [{ pathname: '/', title: 'Home', content: 'Welcome to my site.' }], }); const siteScore = scoreSiteCitability(config); The citability score evaluates: - Content structure and headings - Factual density and specificity - Source attribution - Unique data and statistics - Clear definitions and explanations ## Reports [Section titled “Reports”](#reports) Generate a comprehensive AEO report: import { formatReportJson, formatReportMarkdown, generateReport, resolveConfig } from 'aeo.js'; const config = resolveConfig({ title: 'My Site', url: 'https://mysite.com', pages: [{ pathname: '/', title: 'Home', content: 'Welcome to my site.' }], }); const report = generateReport(config); // Get as markdown console.log(formatReportMarkdown(report)); // Get as JSON console.log(formatReportJson(report)); ## Platform Hints [Section titled “Platform Hints”](#platform-hints) Get platform-specific optimization suggestions: import { auditSite, generatePlatformHints, resolveConfig, scoreSiteCitability } from 'aeo.js'; const config = resolveConfig({ title: 'My Site', url: 'https://mysite.com', pages: [{ pathname: '/', title: 'Home', content: 'Welcome to my site.' }], }); const audit = auditSite(config); const citability = scoreSiteCitability(config); const hints = generatePlatformHints(audit, citability); // Returns platform-specific optimization hints for ChatGPT, Perplexity, Google AI, and Bing Copilot [Previous JSON-LD Recipes](/features/json-ld/) [Next Configuration](/reference/configuration/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # CLI URL: https://aeojs.org/features/cli > Run aeo.js from the command line without any framework integration. ## CLI ## Usage [Section titled “Usage”](#usage) Terminal window npx aeo.js <command> [options] ** [options]"> ## Commands [Section titled “Commands”](#commands) ### generate [Section titled “generate”](#generate) Generate all AEO files (robots.txt, llms.txt, sitemap.xml, etc.): Terminal window npx aeo.js generate npx aeo.js generate --url https://mysite.com --title "My Site" --out public ### init [Section titled “init”](#init) Create an aeo.config.ts configuration file in your project: Terminal window npx aeo.js init This generates a starter config with all options documented. ### check [Section titled “check”](#check) Validate your AEO setup and get a GEO readiness score (0–100). Does not write any files — safe to run in CI: Terminal window npx aeo.js check # formatted output npx aeo.js check --json # machine-readable JSON for scripting Fail a CI build if the score drops below a threshold: Terminal window SCORE=$(npx aeo.js check --json | jq '.audit.score') ["$SCORE" -ge 70] || { echo "GEO score $SCORE below 70"; exit 1; } ### report [Section titled “report”](#report) Deeper analysis than check: per-page citability scores, platform-specific hints (ChatGPT, Claude, Perplexity, Google AI Overviews, Bing Copilot), and a prioritized fix list. Terminal window npx aeo.js report > aeo-report.md npx aeo.js report --json > aeo-report.json aeo-report.mdnpx aeo.js report --json > aeo-report.json"> ## Options [Section titled “Options”](#options) Flag Description --out <dir> Output directory (default: auto-detected) --url <url> Site URL --title <title> Site title --no-widget Disable widget generation --json JSON output (for check and report) --help, -h Show help --version, -v Show version Both --flag value and --flag=value forms are supported. ## Configuration file [Section titled “Configuration file”](#configuration-file) Caution The standalone CLI does not** currently load aeo.config.{ts,js} — it configures itself from CLI flags + defaults only. npx aeo.js init still scaffolds the file as the canonical place for your settings, but today it’s consumed by framework integrations rather than the CLI itself. Create one with npx aeo.js init: import { defineConfig } from 'aeo.js'; export default defineConfig({ title: 'My Site', url: 'https://mysite.com', description: 'A site optimized for AI discovery', outDir: 'public', }); Import it into your framework config so the integration picks it up: vite.config.ts import aeoConfig from './aeo.config'; import { aeoVitePlugin } from 'aeo.js/vite'; export default { plugins: [aeoVitePlugin(aeoConfig)] }; For raw CLI usage on a static site, pass values directly: Terminal window npx aeo.js generate --url https://mysite.com --title "My Site" --out public See the full [Configuration reference](/reference/configuration/) for all options. A complete CLI reference with every flag, exit codes, JSON output shapes, framework auto-detection table, and CI scripting patterns is in [docs/cli.md on GitHub](https://github.com/multivmlabs/aeo.js/blob/main/docs/cli.md). [Previous Widget](/features/widget/) [Next Schema & Open Graph](/features/schema-og/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Generated Files URL: https://aeojs.org/features/generated-files > All the files aeo.js generates and what they ## Generated Files After building, aeo.js generates these files in your output directory: ## robots.txt [Section titled “robots.txt”](#robotstxt) AI-crawler-aware robots directives. Includes rules for all known AI crawlers (GPTBot, ClaudeBot, PerplexityBot, etc.) with sensible defaults. User-agent: * Allow: / User-agent: GPTBot Allow: / User-agent: ClaudeBot Allow: / ## llms.txt [Section titled “llms.txt”](#llmstxt) A concise, LLM-readable summary of your site. This is the first file AI crawlers look for — it tells them what your site is about and where to find content. # My Site A site optimized for AI discovery ## Pages - [Home](https://mysite.com/) - [About](https://mysite.com/about) - [Blog](https://mysite.com/blog) ## llms-full.txt [Section titled “llms-full.txt”](#llms-fulltxt) Full concatenated content of all pages in a single file. Useful for LLMs that want to ingest your entire site at once. ## sitemap.xml [Section titled “sitemap.xml”](#sitemapxml) Standard XML sitemap for search engines and AI crawlers. ## docs.json [Section titled “docs.json”](#docsjson) A structured documentation manifest: { "name": "My Site", "description": "A site optimized for AI discovery", "baseUrl": "https://mysite.com", "totalDocs": 5, "docs": [{ "title": "Home", "path": "/", "markdownUrl": "https://mysite.com/index.md", "htmlUrl": "https://mysite.com/", "content": "..." }] } ## ai-index.json [Section titled “ai-index.json”](#ai-indexjson) An AI-optimized content index designed for RAG (Retrieval-Augmented Generation) pipelines: [{ "id": "index", "url": "https://mysite.com/", "title": "Home", "content": "Full page content in markdown...", "description": "Page description", "keywords": ["keyword1", "keyword2"] }] ## Raw Markdown [Section titled “Raw Markdown”](#raw-markdown) One .md file per page, extracted from your rendered HTML: public/ index.md # Markdown for / about.md # Markdown for /about blog.md # Markdown for /blog ## Toggling generators [Section titled “Toggling generators”](#toggling-generators) You can enable or disable individual generators: { generators: { robotsTxt: true, llmsTxt: true, llmsFullTxt: true, rawMarkdown: true, manifest: true, sitemap: true, aiIndex: true, schema: true, } } [Previous Vanilla JS / Static HTML](/frameworks/vanilla/) [Next Widget](/features/widget/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # JSON-LD Recipes URL: https://aeojs.org/features/json-ld > Copy-paste structured-data recipes for FAQ, HowTo, Product, Article, Recipe, Event, VideoObject, and BreadcrumbList — each paired with an XSS-safe serializer. ## JSON-LD Recipes aeo.js auto-generates WebSite, Organization, and WebPage schemas when schema.enabled: true. For richer page-type-specific schemas, drop these into your page templates. ## The safe serializer [Section titled “The safe serializer”](#the-safe-serializer) JSON.stringify(...) does **not** escape </script>. A schema value containing </script> (or U+2028 / U+2029) breaks out of the script block and executes as JavaScript. Always run JSON-LD payloads through this helper before injection: - lib/serialize-json-ld.ts export function serializeJsonForHtml(value: unknown): string { return JSON.stringify(value) .replace(/</g, '\\u003C') .replace(/>/g, '\\u003E') .replace(/&/g, '\\u0026') .replace(/\u2028/g, '\\u2028') .replace(/\u2029/g, '\\u2029'); } **/g, '\\u003E') .replace(/&/g, '\\u0026') .replace(/\u2028/g, '\\u2028') .replace(/\u2029/g, '\\u2029');}"> Note aeo.js’s own auto-generated JSON-LD already uses this serializer internally. The recipes below are for custom** JSON-LD you add on top. ## FAQ Page [Section titled “FAQ Page”](#faq-page) const faqSchema = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: [{ '@type': 'Question', name: 'What is Answer Engine Optimization?', acceptedAnswer: { '@type': 'Answer', text: 'AEO is the practice of making your content discoverable and citable by AI-powered answer engines like ChatGPT, Claude, and Perplexity.', }, },], }; ** aeo.js auto-detects** FAQ patterns (heading ending with ? + answer paragraph) and emits this schema for you when schema.enabled: true. ## HowTo [Section titled “HowTo”](#howto) const howToSchema = { '@context': 'https://schema.org', '@type': 'HowTo', name: 'How to deploy a Next.js site to Vercel', totalTime: 'PT5M', step: [{ '@type': 'HowToStep', position: 1, name: 'Install CLI', text: 'Run `npm install -g vercel`.' }, { '@type': 'HowToStep', position: 2, name: 'Login', text: 'Run `vercel login`.' }, { '@type': 'HowToStep', position: 3, name: 'Deploy', text: 'Run `vercel --prod`.' },], }; ** aeo.js auto-detects** Step 1: / Step 2: heading patterns. ## Article / BlogPosting [Section titled “Article / BlogPosting”](#article--blogposting) const articleSchema = { '@context': 'https://schema.org', '@type': 'BlogPosting', headline: 'Optimizing your site for AI search engines in 2026', image: 'https://mysite.com/og/article-cover.png', datePublished: '2026-05-14T10:00:00Z', dateModified: '2026-05-14T10:00:00Z', author: { '@type': 'Person', name: 'Jane Author' }, publisher: { '@type': 'Organization', name: 'My Site', logo: { '@type': 'ImageObject', url: 'https://mysite.com/logo.png' }, }, }; ** Caution Always use ISO-8601 strings for datePublished / dateModified. A raw Date object passed through a template literal renders as "Thu May 14 2026 ..." and breaks validators. Wrap with new Date(d).toISOString(). ## Product [Section titled “Product”](#product) const productSchema = { '@context': 'https://schema.org', '@type': 'Product', name: 'Acme Espresso Machine', description: 'A semi-automatic espresso machine with built-in grinder.', image: ['https://mysite.com/products/espresso/cover.jpg'], sku: 'ACM-ESP-001', brand: { '@type': 'Brand', name: 'Acme' }, offers: { '@type': 'Offer', url: 'https://mysite.com/products/espresso', priceCurrency: 'USD', price: '899.00', availability: 'https://schema.org/InStock', }, aggregateRating: { '@type': 'AggregateRating', ratingValue: '4.7', reviewCount: '142', }, }; ## BreadcrumbList [Section titled “BreadcrumbList”](#breadcrumblist) const breadcrumbSchema = { '@context': 'https://schema.org', '@type': 'BreadcrumbList', itemListElement: [{ '@type': 'ListItem', position: 1, name: 'Home', item: 'https://mysite.com/' }, { '@type': 'ListItem', position: 2, name: 'Blog', item: 'https://mysite.com/blog' }, { '@type': 'ListItem', position: 3, name: 'Article Title' },], }; ## Injecting safely — per framework [Section titled “Injecting safely — per framework”](#injecting-safely--per-framework) [Next.js](#tab-panel-0) - [Astro](#tab-panel-1) - [Nuxt](#tab-panel-2) - [Svelte](#tab-panel-3) import { serializeJsonForHtml } from '@/lib/serialize-json-ld'; <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: serializeJsonForHtml(faqSchema) }} /> <script lang="ts"> import { serializeJsonForHtml } from './lib/serialize-json-ld'; const schema = serializeJsonForHtml(faqSchema); </script> <svelte:head> <script type="application/ld+json">{@html schema}</script> </svelte:head>  "> ## Validation [Section titled “Validation”](#validation) After deploying, paste your URL into one of these: - [Schema Markup Validator](https://validator.schema.org/) — official, quickest - [Google Rich Results Test](https://search.google.com/test/rich-results) — Google rich-result eligibility - [Bing Webmaster URL Inspection](https://www.bing.com/webmasters/url-inspection) — Bing/Copilot-specific feedback Note Full catalog (including Recipe**, **Event**, **VideoObject**, and more per-framework injection variants like React Helmet and vanilla HTML) is in [docs/json-ld.md on GitHub](https://github.com/multivmlabs/aeo.js/blob/main/docs/json-ld.md). [Previous Schema & Open Graph](/features/schema-og/) [Next Audit & Citability](/features/audit/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Schema & Open Graph URL: https://aeojs.org/features/schema-og > Auto-generated JSON-LD structured data and Open Graph meta tags. ## Schema & Open Graph aeo.js can generate JSON-LD structured data and Open Graph meta tags for your pages. ## JSON-LD Schema [Section titled “JSON-LD Schema”](#json-ld-schema) Enable schema generation in your config: - { schema: { enabled: true, organization: { name: 'My Company', url: 'https://mysite.com', logo: 'https://mysite.com/logo.png', sameAs: ['https://twitter.com/mycompany', 'https://github.com/mycompany',], }, defaultType: 'WebPage', // or 'Article' }, } ** This generates <script type="application/ld+json"> blocks with: Organization** schema for your site - **WebPage** or **Article** schema for each page - Proper @context, @type, name, description, and url fields ## Open Graph tags [Section titled “Open Graph tags”](#open-graph-tags) Enable OG tag generation: { og: { enabled: true, image: 'https://mysite.com/og.png', twitterHandle: '@mycompany', type: 'website', // or 'article' }, } This generates meta tags like: <meta property="og:title" content="Page Title" /> <meta property="og:description" content="Page description" /> <meta property="og:image" content="https://mysite.com/og.png" /> <meta property="og:url" content="https://mysite.com/page" /> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:site" content="@mycompany" /> "> ## Programmatic API [Section titled “Programmatic API”](#programmatic-api) The lower-level helpers expect a resolved config and a page entry. import { generateJsonLdScript, generateOGTags, generateOGTagsHtml, generateSchemaObjects, resolveConfig, } from 'aeo.js'; const page = { pathname: '/page', title: 'Page Title', description: 'Page description', content: 'Page content', }; const resolvedConfig = resolveConfig({ title: 'My Company', description: 'My company website', url: 'https://mysite.com', pages: [page], }); // Get schema objects const schemas = generateSchemaObjects(resolvedConfig); // Get a <script> tag string const script = generateJsonLdScript([...schemas.site, ...(schemas.pages[page.pathname] ?? []),]); // Get OG meta tag objects const tags = generateOGTags(page, resolvedConfig); // Get OG meta tags as HTML string const html = generateOGTagsHtml(page, resolvedConfig); tag stringconst script = generateJsonLdScript([ ...schemas.site, ...(schemas.pages[page.pathname] ?? []),]);// Get OG meta tag objectsconst tags = generateOGTags(page, resolvedConfig);// Get OG meta tags as HTML stringconst html = generateOGTagsHtml(page, resolvedConfig);"> Tip Schema and OG generators work independently — you can enable one without the other. [Previous CLI](/features/cli/) [Next JSON-LD Recipes](/features/json-ld/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Human/AI Widget URL: https://aeojs.org/features/widget > The drop-in toggle that shows how AI sees your pages. ## Human/AI Widget The Human/AI widget is a floating toggle that lets visitors switch between the normal page and its AI-readable markdown version. ## How it works [Section titled “How it works”](#how-it-works) When a visitor clicks **AI**, the widget: - Fetches the .md file for the current page - Falls back to extracting markdown from the live DOM if no .md exists - Displays the markdown in a slide-out panel - Offers copy-to-clipboard and download actions ## Automatic injection [Section titled “Automatic injection”](#automatic-injection) Framework plugins (Astro, Vite, Nuxt, Angular) inject the widget automatically. No extra code needed. ## Manual setup (Next.js / React) [Section titled “Manual setup (Next.js / React)”](#manual-setup-nextjs--react) For Next.js or other manual setups, create a client component: 'use client'; import { useEffect } from 'react'; export function AeoWidgetLoader() { useEffect(() => { import('aeo.js/widget').then(({ AeoWidget }) => { new AeoWidget({ config: { title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right' }, }, }); }); }, []); return null; } { import('aeo.js/widget').then(({ AeoWidget }) => { new AeoWidget({ config: { title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right' }, }, }); }); }, []); return null;}"> ## Framework components [Section titled “Framework components”](#framework-components) aeo.js ships React, Vue, and Svelte wrapper components: ### React [Section titled “React”](#react) import { AeoReactWidget } from 'aeo.js/react'; <AeoReactWidget config={{ title: 'My Site', url: 'https://mysite.com' }} /> "> ### Vue [Section titled “Vue”](#vue) <script setup> import { AeoVueWidget } from 'aeo.js/vue'; </script> <template> <AeoVueWidget :config="{ title: 'My Site', url: 'https://mysite.com' }" /> </template>  "> ## Configuration [Section titled “Configuration”](#configuration) widget: { enabled: true, position: 'bottom-right', // 'bottom-left' | 'top-right' | 'top-left' size: 'default', // 'small' | 'icon-only' humanLabel: 'Human', aiLabel: 'AI', showBadge: true, theme: { background: 'rgba(18, 18, 24, 0.9)', text: '#C0C0C5', accent: '#E8E8EA', badge: '#4ADE80', }, } ## Size variants [Section titled “Size variants”](#size-variants) Default Small Icon size: 'default' size: 'small' size: 'icon-only' Full labels with icons Compact — ~30% smaller Just icons, no labels Tip Set widget.enabled: false to disable the widget entirely while still generating AEO files. [Previous Generated Files](/features/generated-files/) [Next CLI](/features/cli/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Angular URL: https://aeojs.org/frameworks/angular > Use aeo.js with Angular. ## Angular ## Setup [Section titled “Setup”](#setup) - Install the package: Terminal window npm install aeo.js - Add a post-build step to your package.json: { "scripts": { "postbuild": "node -e \"import('aeo.js/angular').then(m => m.postBuild({ title: 'My App', url: 'https://myapp.com' }))\"" } } m.postBuild({ title: 'My App', url: 'https://myapp.com' }))\"" }}"> - Build your app: Terminal window npm run build ## How it works [Section titled “How it works”](#how-it-works) The Angular plugin: - Reads angular.json to auto-detect the output directory (dist/<project>/browser/) - Scans route config files (*.routes.ts) and component directories for routes - Scans pre-rendered HTML from the build output for full page content - Injects the widget into index.html automatically ## Programmatic usage [Section titled “Programmatic usage”](#programmatic-usage) You can also generate AEO files from source routes without building: import { generate } from 'aeo.js/angular'; await generate({ title: 'My App', url: 'https://myapp.com' }); Note Angular SSR (with @angular/ssr) is supported. The plugin will scan pre-rendered HTML for content extraction. ## Configuration [Section titled “Configuration”](#configuration) Pass any [AeoConfig](/reference/configuration/) options to postBuild or generate: import { postBuild } from 'aeo.js/angular'; await postBuild({ title: 'My App', url: 'https://myapp.com', generators: { robotsTxt: true, llmsTxt: true, schema: true, }, }); [Previous Nuxt](/frameworks/nuxt/) [Next Webpack](/frameworks/webpack/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Astro URL: https://aeojs.org/frameworks/astro > Use aeo.js with Astro. ## Astro ## Setup [Section titled “Setup”](#setup) - Install the package: Terminal window npm install aeo.js - Add the integration to your Astro config: astro.config.mjs import { defineConfig } from 'astro/config'; import { aeoAstroIntegration } from 'aeo.js/astro'; export default defineConfig({ site: 'https://mysite.com', integrations: [aeoAstroIntegration({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }),], }); - Build your site: Terminal window npm run build ## How it works [Section titled “How it works”](#how-it-works) The Astro integration: - Hooks into the Astro build pipeline via astro:build:done - Scans all rendered HTML pages for content extraction - Generates all AEO files in your output directory - Automatically injects the Human/AI widget - Persists the widget across View Transitions ## Configuration [Section titled “Configuration”](#configuration) Pass any [AeoConfig](/reference/configuration/) options to the integration: aeoAstroIntegration({ title: 'My Site', url: 'https://mysite.com', generators: { robotsTxt: true, llmsTxt: true, sitemap: false, // Astro has its own sitemap }, widget: { position: 'bottom-left', theme: { accent: '#6366f1', }, }, }); [Previous Quick Start](/getting-started/quick-start/) [Next Next.js](/frameworks/nextjs/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Next.js URL: https://aeojs.org/frameworks/nextjs > Use aeo.js with Next.js. ## Next.js ## Setup [Section titled “Setup”](#setup) - Install the package: Terminal window npm install aeo.js - Wrap your Next.js config with withAeo: next.config.mjs import { withAeo } from 'aeo.js/next'; export default withAeo({ aeo: { title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }, }); - Add the post-build step to your package.json: { "scripts": { "postbuild": "node -e \"import('aeo.js/next').then(m => m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\"" } } m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\"" }}"> Tip The postbuild step is needed because Next.js pre-renders pages during build. The post-build step scans the rendered HTML to extract full page content. ## Widget [Section titled “Widget”](#widget) For Next.js, add the widget manually as a client component: // app/layout.tsx (or any client component) 'use client'; import { useEffect } from 'react'; export function AeoWidgetLoader() { useEffect(() => { import('aeo.js/widget').then(({ AeoWidget }) => { new AeoWidget({ config: { title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right' }, }, }); }); }, []); return null; } { import('aeo.js/widget').then(({ AeoWidget }) => { new AeoWidget({ config: { title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right' }, }, }); }); }, []); return null;}"> ## Configuration [Section titled “Configuration”](#configuration) Pass any [AeoConfig](/reference/configuration/) options in the aeo key: export default withAeo({ aeo: { title: 'My Site', url: 'https://mysite.com', generators: { robotsTxt: true, llmsTxt: true, schema: true, }, widget: { enabled: true, position: 'bottom-right', }, }, }); [Previous Astro](/frameworks/astro/) [Next Vite](/frameworks/vite/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Nuxt URL: https://aeojs.org/frameworks/nuxt > Use aeo.js with Nuxt 3. ## Nuxt ## Setup [Section titled “Setup”](#setup) - Install the package: Terminal window npm install aeo.js - Add the module to your Nuxt config: nuxt.config.ts export default defineNuxtConfig({ modules: ['aeo.js/nuxt'], aeo: { title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }, }); ## How it works [Section titled “How it works”](#how-it-works) The Nuxt module: - Scans your pages/ directory for routes - Generates AEO files during dev and production builds - Scans pre-rendered HTML from .output/public/ for full page content - Injects the widget as a client-side Nuxt plugin - Adds <link> and <meta> tags for AEO discoverability ## Configuration [Section titled “Configuration”](#configuration) Pass any [AeoConfig](/reference/configuration/) options in the aeo key: export default defineNuxtConfig({ modules: ['aeo.js/nuxt'], aeo: { title: 'My Site', url: 'https://mysite.com', generators: { robotsTxt: true, llmsTxt: true, rawMarkdown: true, }, widget: { enabled: true, position: 'bottom-left', }, }, }); [Previous Vite](/frameworks/vite/) [Next Angular](/frameworks/angular/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Vanilla JS / Static HTML URL: https://aeojs.org/frameworks/vanilla > Use aeo.js with a plain HTML site, hand-rolled JS, or any static-site generator — no framework required. ## Vanilla JS / Static HTML aeo.js works on any project that produces static HTML. Use the CLI directly — no plugin, no module, no framework. ## Quick Start [Section titled “Quick Start”](#quick-start) - [Zero-install (npx)](#tab-panel-4) - [Installed](#tab-panel-5) - Terminal window npx aeo.js generate --url https://mysite.com --title "My Site" --out public ** Terminal window npm install --save-dev aeo.js npx aeo.js generate --url https://mysite.com --title "My Site" --out public generate walks your output directory, extracts page content, and emits robots.txt, llms.txt, sitemap.xml, ai-index.json, and schema.json next to your HTML. Caution The standalone CLI configures itself from flags only** — it does not load aeo.config.{ts,js}. Pass --url / --title / --out on the command line, or call the package’s API programmatically (see “Calling the API directly” below) to access richer options like contentDir and pages. ## How aeo.js Discovers Your Pages [Section titled “How aeo.js Discovers Your Pages”](#how-aeojs-discovers-your-pages) Source How to set Use when **Built HTML in outDir** --out public (CLI) You have a built static site with *.html files **contentDir** programmatic only — see below You have handwritten .md / .mdx files **pages array** programmatic only — see below Explicit control for runtime-only routes The CLI exposes --out for outDir. For the richer options (contentDir, pages), call the package’s API directly: scripts/aeo.mjs import { generateAEOFiles, resolveConfig } from 'aeo.js'; await generateAEOFiles(resolveConfig({ title: 'My Site', url: 'https://mysite.com', contentDir: 'content', outDir: 'public', pages: [{ pathname: '/', title: 'Home' }], })); ## Common Setups [Section titled “Common Setups”](#common-setups) ### Hand-rolled HTML site [Section titled “Hand-rolled HTML site”](#hand-rolled-html-site) package.json { "scripts": { "build:aeo": "aeo.js generate --url https://mysite.com --title \"My Site\" --out ." } } ### Eleventy / Hugo / Jekyll [Section titled “Eleventy / Hugo / Jekyll”](#eleventy--hugo--jekyll) package.json { "scripts": { "build": "eleventy", "postbuild": "aeo.js generate --url https://mysite.com --title \"My Site\" --out _site" } } For Hugo use --out public; for Jekyll --out _site. The postbuild script runs automatically after npm run build. ### Markdown blog (no framework) [Section titled “Markdown blog (no framework)”](#markdown-blog-no-framework) The CLI’s --out flag covers built HTML; to also pull .md front-matter and bodies from a contentDir, use the programmatic API: scripts/aeo.mjs import { generateAEOFiles, resolveConfig } from 'aeo.js'; await generateAEOFiles(resolveConfig({ title: 'My Blog', url: 'https://myblog.dev', contentDir: 'content', // pull post bodies from here outDir: 'public', // write generated files here })); package.json { "scripts": { "build:aeo": "node scripts/aeo.mjs" } } ## Adding the Widget [Section titled “Adding the Widget”](#adding-the-widget) <script type="module"> import { AeoWidget } from 'https://esm.sh/aeo.js/widget'; new AeoWidget({ config: { title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right', size: 'small' }, }, }); </script> Or install and bundle locally with import { AeoWidget } from 'aeo.js/widget'. ## CI Integration [Section titled “CI Integration”](#ci-integration) - run: npx aeo.js check --json | tee audit.json - run: | SCORE=$(jq '.audit.score' audit.json) ["$SCORE" -ge 70] || { echo "GEO score $SCORE below 70"; exit 1; } Note Full walkthrough with deployment recipes (Vercel, Netlify, Cloudflare, GitHub Pages) is in the [Vanilla Guide on GitHub](https://github.com/multivmlabs/aeo.js/blob/main/docs/vanilla.md). ## Further Reading [Section titled “Further Reading”](#further-reading) [CLI Reference](/features/cli/) — every command, every flag - [JSON-LD Recipes](/features/json-ld/) — FAQ, HowTo, Product, Article, Recipe, Event - [Configuration Reference](/reference/configuration/) [Previous Webpack](/frameworks/webpack/) [Next Generated Files](/features/generated-files/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Vite URL: https://aeojs.org/frameworks/vite > Use aeo.js with Vite (React, Vue, Svelte, etc.). ## Vite ## Setup [Section titled “Setup”](#setup) - Install the package: Terminal window npm install aeo.js - Add the plugin to your Vite config: vite.config.ts import { defineConfig } from 'vite'; import { aeoVitePlugin } from 'aeo.js/vite'; export default defineConfig({ plugins: [aeoVitePlugin({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }),], }); ## How it works [Section titled “How it works”](#how-it-works) The Vite plugin: - Generates AEO files on both vite dev and vite build - Injects the Human/AI widget automatically via HTML transform - Serves dynamic .md files during development (extracts content from your running app) - Detects SPA shells and falls back to client-side DOM extraction - Works with React, Vue, Svelte, or any Vite-based framework ## Configuration [Section titled “Configuration”](#configuration) Pass any [AeoConfig](/reference/configuration/) options to the plugin: aeoVitePlugin({ title: 'My Site', url: 'https://mysite.com', widget: { position: 'top-right', theme: { background: 'rgba(0, 0, 0, 0.85)', accent: '#f59e0b', }, }, }); [Previous Next.js](/frameworks/nextjs/) [Next Nuxt](/frameworks/nuxt/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Webpack URL: https://aeojs.org/frameworks/webpack > Use aeo.js with Webpack. ## Webpack ## Setup [Section titled “Setup”](#setup) - Install the package: Terminal window npm install aeo.js - Add the plugin to your Webpack config: webpack.config.js const { AeoWebpackPlugin } = require('aeo.js/webpack'); module.exports = { plugins: [new AeoWebpackPlugin({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }),], }; ## How it works [Section titled “How it works”](#how-it-works) The Webpack plugin: - Runs during the emit phase of the Webpack compilation - Generates all AEO files in your output directory - Injects the widget into your HTML entry point ## Configuration [Section titled “Configuration”](#configuration) Pass any [AeoConfig](/reference/configuration/) options to the plugin: new AeoWebpackPlugin({ title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right', }, }); [Previous Angular](/frameworks/angular/) [Next Vanilla JS / Static HTML](/frameworks/vanilla/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Installation URL: https://aeojs.org/getting-started/installation > Install aeo.js in your project. ## Installation ## Install the package [Section titled “Install the package”](#install-the-package) - [npm](#tab-panel-6) - [pnpm](#tab-panel-7) - [yarn](#tab-panel-8) - Terminal window npm install aeo.js ** Terminal window pnpm add aeo.js Terminal window yarn add aeo.js ## Or use the CLI directly [Section titled “Or use the CLI directly”](#or-use-the-cli-directly) No installation needed — run it with npx: Terminal window npx aeo.js generate ## Requirements [Section titled “Requirements”](#requirements) Node.js** 18 or later - A framework with a build step that outputs HTML (or use the CLI for any static site) ## Next steps [Section titled “Next steps”](#next-steps) Head to [Quick Start](/getting-started/quick-start/) to add aeo.js to your project, or jump to your framework’s guide: - [Astro](/frameworks/astro/) - [Next.js](/frameworks/nextjs/) - [Vite](/frameworks/vite/) - [Nuxt](/frameworks/nuxt/) - [Angular](/frameworks/angular/) - [Webpack](/frameworks/webpack/) [Previous Introduction](/getting-started/introduction/) [Next Quick Start](/getting-started/quick-start/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Introduction URL: https://aeojs.org/getting-started/introduction > What is aeo.js and why you need Answer Engine Optimization. ## Introduction ## What is Answer Engine Optimization? [Section titled “What is Answer Engine Optimization?”](#what-is-answer-engine-optimization) Answer Engine Optimization (AEO) is the practice of making your website discoverable and citable by AI-powered answer engines like **ChatGPT**, **Claude**, **Perplexity**, and **SearchGPT**. Unlike traditional SEO which focuses on search engine result pages (SERPs), AEO ensures your content is understood and referenced by Large Language Models (LLMs) when they generate answers. ## Why aeo.js? [Section titled “Why aeo.js?”](#why-aeojs) AI crawlers and LLMs look for specific files and formats that most websites don’t provide: - **llms.txt** — A concise summary of your site written for LLMs - **llms-full.txt** — Full content concatenated for deep ingestion - **ai-index.json** — Structured content optimized for RAG pipelines - **docs.json** — Documentation manifest for content discovery - **Raw Markdown** — Per-page .md files for clean content extraction **aeo.js** generates all of these automatically from your existing pages — no manual work required. ## How it works [Section titled “How it works”](#how-it-works) - **Install** the package and add the plugin for your framework - **Build** your site as usual - **aeo.js** scans your output, extracts content, and generates all AEO files - The optional **widget** lets visitors toggle between human and AI views of your pages ## Scope: what aeo.js does and doesn’t influence [Section titled “Scope: what aeo.js does and doesn’t influence”](#scope-what-aeojs-does-and-doesnt-influence) AEO is the **on-site** half of being discoverable by AI engines — there’s an off-site half that aeo.js cannot reach. Setting expectations upfront so you can plan a full strategy: What aeo.js does well Improves machine-readable access to **your own site**: - generates llms.txt, llms-full.txt, ai-index.json, raw markdown copies, JSON-LD schema, and a sitemap - structures content so AI crawlers can fetch, parse, and quote it - audits and scores your page-level citability so you know where to improve What aeo.js cannot influence Off-site signals that AI engines also weigh: - **third-party mentions and reviews** of your product across the web - **inbound links** and how reputable the linking domains are - **community discussions** (Reddit, Hacker News, X, niche forums) and how often you’re cited there - **model training data** — what an LLM “already knows” about you from its pre-training cutoff - **freshness signals** outside your control (independent news, blog roundups, podcasts) Think of aeo.js as a strong foundation — necessary but not sufficient. For full AEO coverage, pair it with the off-site work above: PR, community engagement, and being mentioned where your customers research. ## Supported Frameworks [Section titled “Supported Frameworks”](#supported-frameworks) Framework Import Astro aeo.js/astro Next.js aeo.js/next Vite (React, Vue, Svelte) aeo.js/vite Nuxt aeo.js/nuxt Angular aeo.js/angular Webpack aeo.js/webpack Any (CLI) npx aeo.js generate [Next Installation](/getting-started/installation/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Quick Start URL: https://aeojs.org/getting-started/quick-start > Get aeo.js running in under 2 minutes. ## Quick Start The fastest way to add AEO to your site depends on your framework. ## Astro [Section titled “Astro”](#astro) - Install the package: Terminal window npm install aeo.js - Add the integration to your Astro config: astro.config.mjs import { defineConfig } from 'astro/config'; import { aeoAstroIntegration } from 'aeo.js/astro'; export default defineConfig({ site: 'https://mysite.com', integrations: [aeoAstroIntegration({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }),], }); - Build your site — all AEO files are generated automatically. ## Next.js [Section titled “Next.js”](#nextjs) - Install the package: Terminal window npm install aeo.js - Wrap your Next.js config: next.config.mjs import { withAeo } from 'aeo.js/next'; export default withAeo({ aeo: { title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }, }); - Add the post-build step to package.json: { "scripts": { "postbuild": "node -e \"import('aeo.js/next').then(m => m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\"" } } m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\"" }}"> ## Vite [Section titled “Vite”](#vite) - Install the package: Terminal window npm install aeo.js - Add the plugin to your Vite config: vite.config.ts import { defineConfig } from 'vite'; import { aeoVitePlugin } from 'aeo.js/vite'; export default defineConfig({ plugins: [aeoVitePlugin({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }),], }); ## CLI (any site) [Section titled “CLI (any site)”](#cli-any-site) No framework integration needed: Terminal window npx aeo.js generate --url https://mysite.com --title "My Site" See [CLI docs](/features/cli/) for all commands and options. [Previous Installation](/getting-started/installation/) [Next Astro](/frameworks/astro/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # aeo.js — Answer Engine Optimization for the Modern Web URL: https://aeojs.org > Answer Engine Optimization for the modern web. Make your site discoverable by AI crawlers and LLMs. ## aeo.js [Get Started](/getting-started/introduction/) **Install Audit Generate Config $ ▌ added 1 package in 2s Ready — run npx aeo.js init to get started $ ▌ GEO Readiness Score: 92/100 (Excellent) ══════════════════════════════════════ AI Access: 20/20 Content Structure: 20/20 Schema Presence: 20/20 Meta Quality: 16/20 Citability: 16/20 $ ▌ [aeo.js] Generating AEO files... robots.txt — AI crawler directives llms.txt — LLM summary llms-full.txt — full content for LLMs sitemap.xml — sitemap schema.json — JSON-LD structured data ai-index.json — AI content index Generated 6 files in 42ms // aeo.config.ts import { defineConfig } from 'aeo.js' export default defineConfig({ title: 'My Site', url: 'https://mysite.com', schema: { organization: { name: 'My Co' } }, widget: { size: 'small' }, }); - [Quick Start](#quick-start) - [What is AEO?](#what-is-aeo) - [Why AEO](#why-aeo-matters) - [Widget](#widget) - [Configuration](#configuration) - [Generated Files](#generated-files) - [Checker](#checker) ## Quick Start [Section titled “Quick Start”](#quick-start) - Terminal window npm install aeo.js [Astro](#tab-panel-9) - [Next.js](#tab-panel-10) - [Vite](#tab-panel-11) - [Nuxt](#tab-panel-12) - [Angular](#tab-panel-13) - [Webpack](#tab-panel-14) - [CLI](#tab-panel-15) astro.config.mjs import { defineConfig } from 'astro/config'; import { aeoAstroIntegration } from 'aeo.js/astro'; export default defineConfig({ site: 'https://mysite.com', integrations: [aeoAstroIntegration({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }),], }); next.config.mjs import { withAeo } from 'aeo.js/next'; export default withAeo({ aeo: { title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }, }); Add the post-build step to package.json: { "scripts": { "postbuild": "node -e \"import('aeo.js/next').then(m => m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\"" } } m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\"" }}"> vite.config.ts import { defineConfig } from 'vite'; import { aeoVitePlugin } from 'aeo.js/vite'; export default defineConfig({ plugins: [aeoVitePlugin({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }),], }); nuxt.config.ts export default defineNuxtConfig({ modules: ['aeo.js/nuxt'], aeo: { title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }, }); Add a post-build step to package.json: { "scripts": { "postbuild": "node -e \"import('aeo.js/angular').then(m => m.postBuild({ title: 'My App', url: 'https://myapp.com' }))\"" } } m.postBuild({ title: 'My App', url: 'https://myapp.com' }))\"" }}"> Or generate programmatically: import { generate } from 'aeo.js/angular'; await generate({ title: 'My App', url: 'https://myapp.com' }); webpack.config.js const { AeoWebpackPlugin } = require('aeo.js/webpack'); module.exports = { plugins: [new AeoWebpackPlugin({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }),], }; No framework needed — run standalone: Terminal window # Generate all AEO files npx aeo.js generate --url https://mysite.com --title "My Site" # Scaffold a config file npx aeo.js init # Check your setup npx aeo.js check ## What is AEO? [Section titled “What is AEO?”](#what-is-aeo) Answer Engine Optimization (AEO) is the practice of making your website discoverable and citable by AI-powered answer engines like ChatGPT, Claude, Perplexity, and SearchGPT. aeo.js** auto-generates the files these engines look for and provides a drop-in widget that shows visitors how your site appears to AI. First-class support for Astro, Next.js, Vite, Nuxt, Angular, and Webpack — or run standalone via CLI. ## Why AEO matters [Section titled “Why AEO matters”](#why-aeo-matters) 58% of searches end without a click — AI gives the answer directly 40% of Gen Z prefer AI assistants over traditional search engines 97% of sites have no llms.txt or structured data for AI crawlers 1 min to set up aeo.js generates robots.txt, llms.txt, schema & more If your site isn’t optimized for AI engines, you’re invisible to a growing share of users who never open a search results page. AEO is the new SEO. ## Widget [Section titled “Widget”](#widget) The Human/AI widget lets visitors toggle between the normal page and its AI-readable markdown version. Framework plugins inject it automatically — for Next.js or manual setups: 'use client'; import { useEffect } from 'react'; export function AeoWidgetLoader() { useEffect(() => { import('aeo.js/widget').then(({ AeoWidget }) => { new AeoWidget({ config: { title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right' }, }, }); }); }, []); return null; } { import('aeo.js/widget').then(({ AeoWidget }) => { new AeoWidget({ config: { title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right' }, }, }); }); }, []); return null;}"> React and Vue wrapper components are also available: - [React](#tab-panel-16) - [Vue](#tab-panel-17) import { AeoReactWidget } from 'aeo.js/react'; <AeoReactWidget config={{ title: 'My Site', url: 'https://mysite.com' }} /> "> <script setup> import { AeoVueWidget } from 'aeo.js/vue'; </script> <template> <AeoVueWidget :config="{ title: 'My Site', url: 'https://mysite.com' }" /> </template>  "> ## Configuration [Section titled “Configuration”](#configuration) All frameworks use the same config shape — [see full reference](/reference/configuration/): import { defineConfig } from 'aeo.js'; export default defineConfig({ title: 'My Site', url: 'https://mysite.com', description: 'A site optimized for AI discovery', generators: { robotsTxt: true, llmsTxt: true, llmsFullTxt: true, rawMarkdown: true, sitemap: true, aiIndex: true, schema: true, }, schema: { enabled: true, organization: { name: 'My Company', url: 'https://mysite.com' }, defaultType: 'WebPage', }, og: { enabled: true, image: 'https://mysite.com/og.png', twitterHandle: '@mycompany', }, widget: { enabled: true, position: 'bottom-right', theme: { accent: '#4ADE80', badge: '#4ADE80' }, }, }); ## Generated Files [Section titled “Generated Files”](#generated-files) After building, your output directory contains: public/ ├── robots.txt # AI-crawler directives ├── llms.txt # Short LLM-readable summary ├── llms-full.txt # Full content for LLMs ├── sitemap.xml # Standard sitemap ├── docs.json # Documentation manifest ├── ai-index.json # AI content index ├── index.md # Markdown for / └── about.md # Markdown for /about ## Checker [Section titled “Checker”](#checker) Scan Free — no signup required. Powered by [AEO Checker](https://check.aeojs.org) ## Built by [](https://github.com/rubenmarcus)[](https://github.com/KimHyeongRae0)[](https://github.com/FabioRocha231)[](https://github.com/ribeiroevandro)[](https://github.com/HusseinAdeiza)[](https://github.com/mhanelia) [View all 6 contributors →](/contributors/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # API Reference URL: https://aeojs.org/reference/api > Programmatic API for aeo.js. ## API Reference ## Core [Section titled “Core”](#core) ### defineConfig(config) [Section titled “defineConfig(config)”](#defineconfigconfig) Type-safe configuration helper: import { defineConfig } from 'aeo.js'; export default defineConfig({ title: 'My Site', url: 'https://mysite.com', }); ** ### generateAll(config) [Section titled “generateAll(config)”](#generateallconfig) Generate all AEO files programmatically: import { generateAll } from 'aeo.js'; await generateAll({ title: 'My Site', url: 'https://mysite.com', outDir: 'dist', }); ### resolveConfig(config) [Section titled “resolveConfig(config)”](#resolveconfigconfig) Resolve a partial config into a fully resolved config with defaults: import { resolveConfig } from 'aeo.js'; const resolved = resolveConfig({ title: 'My Site' }); // All fields now have defaults The examples below use resolvedConfig for a config object returned by resolveConfig. ### validateConfig(config) [Section titled “validateConfig(config)”](#validateconfigconfig) Validate a config object and return any errors: import { validateConfig } from 'aeo.js'; const errors = validateConfig(config); ### detectFramework() [Section titled “detectFramework()”](#detectframework) Auto-detect the framework used in the current project: import { detectFramework } from 'aeo.js'; const info = detectFramework(); // { framework: 'next', contentDir: 'pages', outDir: '.next' } ## HTML Extraction [Section titled “HTML Extraction”](#html-extraction) ### htmlToMarkdown(html, pagePath, config) [Section titled “htmlToMarkdown(html, pagePath, config)”](#htmltomarkdownhtml-pagepath-config) Convert HTML to clean markdown: import { htmlToMarkdown } from 'aeo.js'; const md = htmlToMarkdown( '<html><head><title>Hello</title></head><body><main><p>World</p></main></body></html>', '/', { url: 'https://mysite.com' } ); // Returns a markdown document with YAML frontmatter Hello World ', '/', { url: 'https://mysite.com' });// Returns a markdown document with YAML frontmatter"> ### extractTextFromHtml(html) [Section titled “extractTextFromHtml(html)”](#extracttextfromhtmlhtml) Extract plain text from HTML: import { extractTextFromHtml } from 'aeo.js'; const text = extractTextFromHtml('<p>Hello <strong>world</strong></p>'); world** ');"> ### extractTitle(html) / extractDescription(html) [Section titled “extractTitle(html) / extractDescription(html)”](#extracttitlehtml--extractdescriptionhtml) Extract the title or meta description from an HTML document. ### extractJsonLd(html) [Section titled “extractJsonLd(html)”](#extractjsonldhtml) Extract JSON-LD structured data from an HTML document. ## Schema [Section titled “Schema”](#schema) ### generateSchemaObjects(config) [Section titled “generateSchemaObjects(config)”](#generateschemaobjectsconfig) Generate JSON-LD schema objects: import { generateSchemaObjects } from 'aeo.js'; const schemas = generateSchemaObjects(resolvedConfig); ### generateJsonLdScript(schemas) [Section titled “generateJsonLdScript(schemas)”](#generatejsonldscriptschemas) Generate a <script type="application/ld+json"> tag: import { generateJsonLdScript, generateSiteSchemas } from 'aeo.js'; const schemas = generateSiteSchemas(resolvedConfig); const script = generateJsonLdScript(schemas); ### generateSiteSchemas(config) / generatePageSchemas(page, config) [Section titled “generateSiteSchemas(config) / generatePageSchemas(page, config)”](#generatesiteschemasconfig--generatepageschemaspage-config) Generate schemas for the site or individual pages. ## Open Graph [Section titled “Open Graph”](#open-graph) ### generateOGTags(page, config) [Section titled “generateOGTags(page, config)”](#generateogtagspage-config) Returns an array of MetaTag objects: import { generateOGTags } from 'aeo.js'; const tags = generateOGTags( { pathname: '/', title: 'Home' }, resolvedConfig ); // [{ property: 'og:title', content: 'Home' }, ...] ### generateOGTagsHtml(page, config) [Section titled “generateOGTagsHtml(page, config)”](#generateogtagshtmlpage-config) Returns OG tags as an HTML string. ## Audit [Section titled “Audit”](#audit) ### auditSite(config) [Section titled “auditSite(config)”](#auditsiteconfig) Audit a site for AEO best practices: import { auditSite, formatAuditReport, getGrade, resolveConfig } from 'aeo.js'; const config = resolveConfig({ title: 'My Site', url: 'https://mysite.com', pages: [{ pathname: '/', title: 'Home', content: 'Welcome to my site.' }], }); const result = auditSite(config); console.log(formatAuditReport(result)); console.log(getGrade(result.score)); // 'Excellent', 'Good', 'Fair', etc. ## Citability [Section titled “Citability”](#citability) ### scorePageCitability(page) [Section titled “scorePageCitability(page)”](#scorepagecitabilitypage) Score how likely a page is to be cited by AI: import { scorePageCitability, formatPageCitability } from 'aeo.js'; const score = scorePageCitability({ pathname: '/', title: 'Home', content: '# Home\n\nMy site publishes practical guides for AI-ready content.', }); console.log(formatPageCitability(score)); ### scoreSiteCitability(config) [Section titled “scoreSiteCitability(config)”](#scoresitecitabilityconfig) Score citability across your entire site. ## Reports [Section titled “Reports”](#reports) ### generateReport(config) [Section titled “generateReport(config)”](#generatereportconfig) Generate a comprehensive AEO report: import { generateReport, formatReportMarkdown } from 'aeo.js'; const report = generateReport(resolvedConfig); console.log(formatReportMarkdown(report)); ## Platform Hints [Section titled “Platform Hints”](#platform-hints) ### generatePlatformHints(audit, citability) [Section titled “generatePlatformHints(audit, citability)”](#generateplatformhintsaudit-citability) Generate platform-specific optimization hints from audit and citability results: import { auditSite, generatePlatformHints, scoreSiteCitability } from 'aeo.js'; const audit = auditSite(resolvedConfig); const citability = scoreSiteCitability(resolvedConfig); const hints = generatePlatformHints(audit, citability); ## Types [Section titled “Types”](#types) All types are exported from the main entry: import type { AeoConfig, ResolvedAeoConfig, PageEntry, DocEntry, AeoManifest, MarkdownFile, ManifestEntry, AIIndexEntry, FrameworkType, FrameworkInfo, AuditResult, AuditCategory, AuditIssue, MetaTag, PageCitabilityResult, SiteCitabilityResult, CitabilityDimension, ContentHint, AeoReport, PlatformHint, } from 'aeo.js'; [Previous Configuration](/reference/configuration/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Configuration URL: https://aeojs.org/reference/configuration > Full configuration reference for aeo.js. ## Configuration All framework plugins and the CLI accept the same AeoConfig object. ## Full example [Section titled “Full example”](#full-example) import { defineConfig } from 'aeo.js'; export default defineConfig({ // Required title: 'My Site', url: 'https://mysite.com', // Optional description: 'A description of your site', contentDir: 'docs', // Directory with handwritten .md files outDir: 'public', // Output directory for generated files // Toggle individual generators generators: { robotsTxt: true, llmsTxt: true, llmsFullTxt: true, rawMarkdown: true, manifest: true, sitemap: true, aiIndex: true, schema: true, }, // Configure ai-index.json generation aiIndex: { maxChunkLength: 2000, maxKeywords: 10, }, // Customize robots.txt robots: { allow: ['/'], disallow: ['/admin'], crawlDelay: 0, sitemap: 'https://mysite.com/sitemap.xml', }, // JSON-LD structured data schema: { enabled: true, organization: { name: 'My Company', url: 'https://mysite.com', logo: 'https://mysite.com/logo.png', sameAs: ['https://twitter.com/mycompany'], }, defaultType: 'WebPage', }, // Open Graph meta tags og: { enabled: true, image: 'https://mysite.com/og.png', twitterHandle: '@mycompany', type: 'website', }, // Widget configuration widget: { enabled: true, position: 'bottom-right', humanLabel: 'Human', aiLabel: 'AI', showBadge: true, theme: { background: 'rgba(18, 18, 24, 0.9)', text: '#C0C0C5', accent: '#E8E8EA', badge: '#4ADE80', }, }, }); ## Options reference [Section titled “Options reference”](#options-reference) ### Top-level [Section titled “Top-level”](#top-level) Option Type Default Description title string '' Site title description string '' Site description url string '' Site URL (used for absolute URLs in generated files) contentDir string 'docs' Directory with handwritten markdown files outDir string auto-detected Output directory for generated files pages PageEntry[] [] Manually specify pages to include ### generators [Section titled “generators”](#generators) Option Type Default Description robotsTxt boolean true Generate robots.txt llmsTxt boolean true Generate llms.txt llmsFullTxt boolean true Generate llms-full.txt rawMarkdown boolean true Generate per-page .md files manifest boolean true Generate docs.json sitemap boolean true Generate sitemap.xml aiIndex boolean true Generate ai-index.json schema boolean false Generate JSON-LD structured data ### aiIndex [Section titled “aiIndex”](#aiindex) Option Type Default Description maxChunkLength number 2000 Target chunk length (soft limit). Chunks split on \n\n paragraph boundaries, so a single long paragraph can exceed this value. Set with embedding-model token limits in mind. maxKeywords number 10 Maximum number of keywords extracted per ai-index.json entry. ### robots [Section titled “robots”](#robots) Option Type Default Description allow string[] ['/'] Allowed paths disallow string[] [] Disallowed paths crawlDelay number 0 Crawl delay in seconds sitemap string auto Sitemap URL ### schema [Section titled “schema”](#schema) Option Type Default Description enabled boolean false Enable schema generation organization.name string '' Organization name organization.url string '' Organization URL organization.logo string '' Organization logo URL organization.sameAs string[] [] Social profile URLs defaultType 'Article' | 'WebPage' 'WebPage' Default schema type for pages ### og [Section titled “og”](#og) Option Type Default Description enabled boolean false Enable OG tag generation image string '' Default OG image URL twitterHandle string '' Twitter handle (e.g. @company) type 'website' | 'article' 'website' Default OG type ### widget [Section titled “widget”](#widget) Option Type Default Description enabled boolean true Enable the widget position string 'bottom-right' Widget position humanLabel string 'Human' Label for human view aiLabel string 'AI' Label for AI view showBadge boolean true Show the AEO badge theme.background string 'rgba(18, 18, 24, 0.9)' Widget background theme.text string '#C0C0C5' Text color theme.accent string '#E8E8EA' Accent color theme.badge string '#4ADE80' Badge color [Previous Audit & Citability](/features/audit/) [Next API](/reference/api/) Built by [rubenmarcus](https://github.com/rubenmarcus) & [multivmlabs](https://github.com/multivmlabs) --- # Audit & Citability Source: docs/features/audit.mdx > Audit your AEO setup and measure your site's citability score. ### Site Audit The `auditSite` function checks your site for AEO best practices and returns a detailed report: ```ts import { auditSite, formatAuditReport, getGrade, resolveConfig } from 'aeo.js'; const config = resolveConfig({ title: 'My Site', url: 'https://mysite.com', pages: [{ pathname: '/', title: 'Home', content: 'Welcome to my site.' }], }); const result = auditSite(config); console.log(formatAuditReport(result)); console.log('Grade:', getGrade(result.score)); ``` The audit checks for: - Presence of `robots.txt`, `llms.txt`, `llms-full.txt` - Sitemap accessibility - Structured data (JSON-LD) - Open Graph meta tags - AI crawler accessibility You can also run it from the CLI: ```bash npx aeo.js check ``` ### Citability Score Measure how likely AI engines are to cite your content: ```ts import { formatPageCitability, resolveConfig, scorePageCitability, scoreSiteCitability } from 'aeo.js'; // Score a single page const pageScore = scorePageCitability({ pathname: '/', title: 'Home', content: '# Home\n\nMy site publishes practical guides for AI-ready content.', }); console.log(formatPageCitability(pageScore)); // Score the whole site const config = resolveConfig({ title: 'My Site', url: 'https://mysite.com', pages: [{ pathname: '/', title: 'Home', content: 'Welcome to my site.' }], }); const siteScore = scoreSiteCitability(config); ``` The citability score evaluates: - Content structure and headings - Factual density and specificity - Source attribution - Unique data and statistics - Clear definitions and explanations ### Reports Generate a comprehensive AEO report: ```ts import { formatReportJson, formatReportMarkdown, generateReport, resolveConfig } from 'aeo.js'; const config = resolveConfig({ title: 'My Site', url: 'https://mysite.com', pages: [{ pathname: '/', title: 'Home', content: 'Welcome to my site.' }], }); const report = generateReport(config); // Get as markdown console.log(formatReportMarkdown(report)); // Get as JSON console.log(formatReportJson(report)); ``` ### Platform Hints Get platform-specific optimization suggestions: ```ts import { auditSite, generatePlatformHints, resolveConfig, scoreSiteCitability } from 'aeo.js'; const config = resolveConfig({ title: 'My Site', url: 'https://mysite.com', pages: [{ pathname: '/', title: 'Home', content: 'Welcome to my site.' }], }); const audit = auditSite(config); const citability = scoreSiteCitability(config); const hints = generatePlatformHints(audit, citability); // Returns platform-specific optimization hints for ChatGPT, Perplexity, Google AI, and Bing Copilot ``` --- # CLI Source: docs/features/cli.mdx > Run aeo.js from the command line without any framework integration. ### Usage ```bash npx aeo.js [options] ``` ### Commands #### `generate` Generate all AEO files (robots.txt, llms.txt, sitemap.xml, etc.): ```bash npx aeo.js generate npx aeo.js generate --url https://mysite.com --title "My Site" --out public ``` #### `init` Create an `aeo.config.ts` configuration file in your project: ```bash npx aeo.js init ``` This generates a starter config with all options documented. #### `check` Validate your AEO setup and get a GEO readiness score (0–100). Does not write any files — safe to run in CI: ```bash npx aeo.js check # formatted output npx aeo.js check --json # machine-readable JSON for scripting ``` Fail a CI build if the score drops below a threshold: ```bash SCORE=$(npx aeo.js check --json | jq '.audit.score') [ "$SCORE" -ge 70 ] || { echo "GEO score $SCORE below 70"; exit 1; } ``` #### `report` Deeper analysis than `check`: per-page citability scores, platform-specific hints (ChatGPT, Claude, Perplexity, Google AI Overviews, Bing Copilot), and a prioritized fix list. ```bash npx aeo.js report > aeo-report.md npx aeo.js report --json > aeo-report.json ``` ### Options | Flag | Description | |------|-------------| | `--out ` | Output directory (default: auto-detected) | | `--url ` | Site URL | | `--title ` | Site title | | `--no-widget` | Disable widget generation | | `--json` | JSON output (for `check` and `report`) | | `--help`, `-h` | Show help | | `--version`, `-v` | Show version | Both `--flag value` and `--flag=value` forms are supported. ### Configuration file import { Aside } from '@astrojs/starlight/components'; <Aside type="caution"> The standalone CLI does **not** currently load `aeo.config.{ts,js}` — it configures itself from CLI flags + defaults only. `npx aeo.js init` still scaffolds the file as the canonical place for your settings, but today it's consumed by framework integrations rather than the CLI itself. </Aside> Create one with `npx aeo.js init`: ```ts import { defineConfig } from 'aeo.js'; export default defineConfig({ title: 'My Site', url: 'https://mysite.com', description: 'A site optimized for AI discovery', outDir: 'public', }); ``` Import it into your framework config so the integration picks it up: ```ts // vite.config.ts import aeoConfig from './aeo.config'; import { aeoVitePlugin } from 'aeo.js/vite'; export default { plugins: [aeoVitePlugin(aeoConfig)] }; ``` For raw CLI usage on a static site, pass values directly: ```bash npx aeo.js generate --url https://mysite.com --title "My Site" --out public ``` See the full [Configuration reference](/reference/configuration/) for all options. A complete CLI reference with every flag, exit codes, JSON output shapes, framework auto-detection table, and CI scripting patterns is in [docs/cli.md on GitHub](https://github.com/multivmlabs/aeo.js/blob/main/docs/cli.md). --- # Generated Files Source: docs/features/generated-files.mdx > All the files aeo.js generates and what they're for. After building, aeo.js generates these files in your output directory: ### robots.txt AI-crawler-aware robots directives. Includes rules for all known AI crawlers (GPTBot, ClaudeBot, PerplexityBot, etc.) with sensible defaults. ```txt User-agent: * Allow: / User-agent: GPTBot Allow: / User-agent: ClaudeBot Allow: / ``` ### llms.txt A concise, LLM-readable summary of your site. This is the first file AI crawlers look for — it tells them what your site is about and where to find content. ```txt ## My Site A site optimized for AI discovery ### Pages - [Home](https://mysite.com/) - [About](https://mysite.com/about) - [Blog](https://mysite.com/blog) ``` ### llms-full.txt Full concatenated content of all pages in a single file. Useful for LLMs that want to ingest your entire site at once. ### sitemap.xml Standard XML sitemap for search engines and AI crawlers. ### docs.json A structured documentation manifest: ```json { "name": "My Site", "description": "A site optimized for AI discovery", "baseUrl": "https://mysite.com", "totalDocs": 5, "docs": [ { "title": "Home", "path": "/", "markdownUrl": "https://mysite.com/index.md", "htmlUrl": "https://mysite.com/", "content": "..." } ] } ``` ### ai-index.json An AI-optimized content index designed for RAG (Retrieval-Augmented Generation) pipelines: ```json [ { "id": "index", "url": "https://mysite.com/", "title": "Home", "content": "Full page content in markdown...", "description": "Page description", "keywords": ["keyword1", "keyword2"] } ] ``` ### Raw Markdown One `.md` file per page, extracted from your rendered HTML: ``` public/ index.md # Markdown for / about.md # Markdown for /about blog.md # Markdown for /blog ``` ### Toggling generators You can enable or disable individual generators: ```js { generators: { robotsTxt: true, llmsTxt: true, llmsFullTxt: true, rawMarkdown: true, manifest: true, sitemap: true, aiIndex: true, schema: true, } } ``` --- # JSON-LD Recipes Source: docs/features/json-ld.mdx > Copy-paste structured-data recipes for FAQ, HowTo, Product, Article, Recipe, Event, VideoObject, and BreadcrumbList — each paired with an XSS-safe serializer. import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; aeo.js auto-generates `WebSite`, `Organization`, and `WebPage` schemas when `schema.enabled: true`. For richer page-type-specific schemas, drop these into your page templates. ### The safe serializer `JSON.stringify(...)` does **not** escape `</script>`. A schema value containing `</script>` (or U+2028 / U+2029) breaks out of the script block and executes as JavaScript. Always run JSON-LD payloads through this helper before injection: ```ts // lib/serialize-json-ld.ts export function serializeJsonForHtml(value: unknown): string { return JSON.stringify(value) .replace(/</g, '\\u003C') .replace(/>/g, '\\u003E') .replace(/&/g, '\\u0026') .replace(/\u2028/g, '\\u2028') .replace(/\u2029/g, '\\u2029'); } ``` <Aside> aeo.js's own auto-generated JSON-LD already uses this serializer internally. The recipes below are for **custom** JSON-LD you add on top. </Aside> ### FAQ Page ```ts const faqSchema = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: [ { '@type': 'Question', name: 'What is Answer Engine Optimization?', acceptedAnswer: { '@type': 'Answer', text: 'AEO is the practice of making your content discoverable and citable by AI-powered answer engines like ChatGPT, Claude, and Perplexity.', }, }, ], }; ``` aeo.js **auto-detects** FAQ patterns (heading ending with `?` + answer paragraph) and emits this schema for you when `schema.enabled: true`. ### HowTo ```ts const howToSchema = { '@context': 'https://schema.org', '@type': 'HowTo', name: 'How to deploy a Next.js site to Vercel', totalTime: 'PT5M', step: [ { '@type': 'HowToStep', position: 1, name: 'Install CLI', text: 'Run `npm install -g vercel`.' }, { '@type': 'HowToStep', position: 2, name: 'Login', text: 'Run `vercel login`.' }, { '@type': 'HowToStep', position: 3, name: 'Deploy', text: 'Run `vercel --prod`.' }, ], }; ``` aeo.js **auto-detects** `Step 1:` / `Step 2:` heading patterns. ### Article / BlogPosting ```ts const articleSchema = { '@context': 'https://schema.org', '@type': 'BlogPosting', headline: 'Optimizing your site for AI search engines in 2026', image: 'https://mysite.com/og/article-cover.png', datePublished: '2026-05-14T10:00:00Z', dateModified: '2026-05-14T10:00:00Z', author: { '@type': 'Person', name: 'Jane Author' }, publisher: { '@type': 'Organization', name: 'My Site', logo: { '@type': 'ImageObject', url: 'https://mysite.com/logo.png' }, }, }; ``` <Aside type="caution"> Always use ISO-8601 strings for `datePublished` / `dateModified`. A raw `Date` object passed through a template literal renders as `"Thu May 14 2026 ..."` and breaks validators. Wrap with `new Date(d).toISOString()`. </Aside> ### Product ```ts const productSchema = { '@context': 'https://schema.org', '@type': 'Product', name: 'Acme Espresso Machine', description: 'A semi-automatic espresso machine with built-in grinder.', image: ['https://mysite.com/products/espresso/cover.jpg'], sku: 'ACM-ESP-001', brand: { '@type': 'Brand', name: 'Acme' }, offers: { '@type': 'Offer', url: 'https://mysite.com/products/espresso', priceCurrency: 'USD', price: '899.00', availability: 'https://schema.org/InStock', }, aggregateRating: { '@type': 'AggregateRating', ratingValue: '4.7', reviewCount: '142', }, }; ``` ### BreadcrumbList ```ts const breadcrumbSchema = { '@context': 'https://schema.org', '@type': 'BreadcrumbList', itemListElement: [ { '@type': 'ListItem', position: 1, name: 'Home', item: 'https://mysite.com/' }, { '@type': 'ListItem', position: 2, name: 'Blog', item: 'https://mysite.com/blog' }, { '@type': 'ListItem', position: 3, name: 'Article Title' }, ], }; ``` ### Injecting safely — per framework <Tabs> <TabItem label="Next.js"> ```tsx import { serializeJsonForHtml } from '@/lib/serialize-json-ld'; <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: serializeJsonForHtml(faqSchema) }} /> ``` </TabItem> <TabItem label="Astro"> ```astro --- import { serializeJsonForHtml } from '../lib/serialize-json-ld'; --- <script type="application/ld+json" set:html={serializeJsonForHtml(faqSchema)} /> ``` </TabItem> <TabItem label="Nuxt"> ```vue <script setup lang="ts"> import { serializeJsonForHtml } from '~/utils/serialize-json-ld'; useHead({ script: [{ type: 'application/ld+json', children: serializeJsonForHtml(faqSchema), }], }); </script> ``` </TabItem> <TabItem label="Svelte"> ```svelte <script lang="ts"> import { serializeJsonForHtml } from './lib/serialize-json-ld'; const schema = serializeJsonForHtml(faqSchema); </script> <svelte:head> <script type="application/ld+json">{@html schema}</script> </svelte:head> ``` </TabItem> </Tabs> ### Validation After deploying, paste your URL into one of these: - [Schema Markup Validator](https://validator.schema.org/) — official, quickest - [Google Rich Results Test](https://search.google.com/test/rich-results) — Google rich-result eligibility - [Bing Webmaster URL Inspection](https://www.bing.com/webmasters/url-inspection) — Bing/Copilot-specific feedback <Aside> Full catalog (including **Recipe**, **Event**, **VideoObject**, and more per-framework injection variants like React Helmet and vanilla HTML) is in [docs/json-ld.md on GitHub](https://github.com/multivmlabs/aeo.js/blob/main/docs/json-ld.md). </Aside> --- # Schema & Open Graph Source: docs/features/schema-og.mdx > Auto-generated JSON-LD structured data and Open Graph meta tags. import { Aside } from '@astrojs/starlight/components'; aeo.js can generate JSON-LD structured data and Open Graph meta tags for your pages. ### JSON-LD Schema Enable schema generation in your config: ```js { schema: { enabled: true, organization: { name: 'My Company', url: 'https://mysite.com', logo: 'https://mysite.com/logo.png', sameAs: [ 'https://twitter.com/mycompany', 'https://github.com/mycompany', ], }, defaultType: 'WebPage', // or 'Article' }, } ``` This generates `<script type="application/ld+json">` blocks with: - **Organization** schema for your site - **WebPage** or **Article** schema for each page - Proper `@context`, `@type`, `name`, `description`, and `url` fields ### Open Graph tags Enable OG tag generation: ```js { og: { enabled: true, image: 'https://mysite.com/og.png', twitterHandle: '@mycompany', type: 'website', // or 'article' }, } ``` This generates meta tags like: ```html <meta property="og:title" content="Page Title" /> <meta property="og:description" content="Page description" /> <meta property="og:image" content="https://mysite.com/og.png" /> <meta property="og:url" content="https://mysite.com/page" /> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:site" content="@mycompany" /> ``` ### Programmatic API The lower-level helpers expect a resolved config and a page entry. ```ts import { generateJsonLdScript, generateOGTags, generateOGTagsHtml, generateSchemaObjects, resolveConfig, } from 'aeo.js'; const page = { pathname: '/page', title: 'Page Title', description: 'Page description', content: 'Page content', }; const resolvedConfig = resolveConfig({ title: 'My Company', description: 'My company website', url: 'https://mysite.com', pages: [page], }); // Get schema objects const schemas = generateSchemaObjects(resolvedConfig); // Get a <script> tag string const script = generateJsonLdScript([ ...schemas.site, ...(schemas.pages[page.pathname] ?? []), ]); // Get OG meta tag objects const tags = generateOGTags(page, resolvedConfig); // Get OG meta tags as HTML string const html = generateOGTagsHtml(page, resolvedConfig); ``` <Aside type="tip"> Schema and OG generators work independently — you can enable one without the other. </Aside> --- # Human/AI Widget Source: docs/features/widget.mdx > The drop-in toggle that shows how AI sees your pages. import { Aside } from '@astrojs/starlight/components'; The Human/AI widget is a floating toggle that lets visitors switch between the normal page and its AI-readable markdown version. ### How it works When a visitor clicks **AI**, the widget: 1. Fetches the `.md` file for the current page 2. Falls back to extracting markdown from the live DOM if no `.md` exists 3. Displays the markdown in a slide-out panel 4. Offers copy-to-clipboard and download actions ### Automatic injection Framework plugins (Astro, Vite, Nuxt, Angular) inject the widget automatically. No extra code needed. ### Manual setup (Next.js / React) For Next.js or other manual setups, create a client component: ```tsx 'use client'; import { useEffect } from 'react'; export function AeoWidgetLoader() { useEffect(() => { import('aeo.js/widget').then(({ AeoWidget }) => { new AeoWidget({ config: { title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right' }, }, }); }); }, []); return null; } ``` ### Framework components aeo.js ships React, Vue, and Svelte wrapper components: #### React ```tsx import { AeoReactWidget } from 'aeo.js/react'; <AeoReactWidget config={{ title: 'My Site', url: 'https://mysite.com' }} /> ``` #### Vue ```vue <script setup> import { AeoVueWidget } from 'aeo.js/vue'; </script> <template> <AeoVueWidget :config="{ title: 'My Site', url: 'https://mysite.com' }" /> </template> ``` ### Configuration ```js widget: { enabled: true, position: 'bottom-right', // 'bottom-left' | 'top-right' | 'top-left' size: 'default', // 'small' | 'icon-only' humanLabel: 'Human', aiLabel: 'AI', showBadge: true, theme: { background: 'rgba(18, 18, 24, 0.9)', text: '#C0C0C5', accent: '#E8E8EA', badge: '#4ADE80', }, } ``` ### Size variants | Default | Small | Icon | |---------|-------|------| | ![Default widget](/widget-default.webp) | ![Small widget](/widget-small.webp) | ![Icon widget](/widget-icon.webp) | | `size: 'default'` | `size: 'small'` | `size: 'icon-only'` | | Full labels with icons | Compact — ~30% smaller | Just icons, no labels | <Aside type="tip"> Set `widget.enabled: false` to disable the widget entirely while still generating AEO files. </Aside> --- # Angular Source: docs/frameworks/angular.mdx > Use aeo.js with Angular. import { Steps, Aside } from '@astrojs/starlight/components'; ### Setup <Steps> 1. Install the package: ```bash npm install aeo.js ``` 2. Add a post-build step to your `package.json`: ```json { "scripts": { "postbuild": "node -e \"import('aeo.js/angular').then(m => m.postBuild({ title: 'My App', url: 'https://myapp.com' }))\"" } } ``` 3. Build your app: ```bash npm run build ``` </Steps> ### How it works The Angular plugin: - Reads `angular.json` to auto-detect the output directory (`dist/<project>/browser/`) - Scans route config files (`*.routes.ts`) and component directories for routes - Scans pre-rendered HTML from the build output for full page content - Injects the widget into `index.html` automatically ### Programmatic usage You can also generate AEO files from source routes without building: ```ts import { generate } from 'aeo.js/angular'; await generate({ title: 'My App', url: 'https://myapp.com' }); ``` <Aside type="note"> Angular SSR (with `@angular/ssr`) is supported. The plugin will scan pre-rendered HTML for content extraction. </Aside> ### Configuration Pass any [AeoConfig](/reference/configuration/) options to `postBuild` or `generate`: ```ts import { postBuild } from 'aeo.js/angular'; await postBuild({ title: 'My App', url: 'https://myapp.com', generators: { robotsTxt: true, llmsTxt: true, schema: true, }, }); ``` --- # Astro Source: docs/frameworks/astro.mdx > Use aeo.js with Astro. import { Steps } from '@astrojs/starlight/components'; ### Setup <Steps> 1. Install the package: ```bash npm install aeo.js ``` 2. Add the integration to your Astro config: ```js // astro.config.mjs import { defineConfig } from 'astro/config'; import { aeoAstroIntegration } from 'aeo.js/astro'; export default defineConfig({ site: 'https://mysite.com', integrations: [ aeoAstroIntegration({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }), ], }); ``` 3. Build your site: ```bash npm run build ``` </Steps> ### How it works The Astro integration: - Hooks into the Astro build pipeline via `astro:build:done` - Scans all rendered HTML pages for content extraction - Generates all AEO files in your output directory - Automatically injects the Human/AI widget - Persists the widget across View Transitions ### Configuration Pass any [AeoConfig](/reference/configuration/) options to the integration: ```js aeoAstroIntegration({ title: 'My Site', url: 'https://mysite.com', generators: { robotsTxt: true, llmsTxt: true, sitemap: false, // Astro has its own sitemap }, widget: { position: 'bottom-left', theme: { accent: '#6366f1', }, }, }); ``` --- # Next.js Source: docs/frameworks/nextjs.mdx > Use aeo.js with Next.js. import { Steps, Aside } from '@astrojs/starlight/components'; ### Setup <Steps> 1. Install the package: ```bash npm install aeo.js ``` 2. Wrap your Next.js config with `withAeo`: ```js // next.config.mjs import { withAeo } from 'aeo.js/next'; export default withAeo({ aeo: { title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }, }); ``` 3. Add the post-build step to your `package.json`: ```json { "scripts": { "postbuild": "node -e \"import('aeo.js/next').then(m => m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\"" } } ``` </Steps> <Aside type="tip"> The `postbuild` step is needed because Next.js pre-renders pages during build. The post-build step scans the rendered HTML to extract full page content. </Aside> ### Widget For Next.js, add the widget manually as a client component: ```tsx // app/layout.tsx (or any client component) 'use client'; import { useEffect } from 'react'; export function AeoWidgetLoader() { useEffect(() => { import('aeo.js/widget').then(({ AeoWidget }) => { new AeoWidget({ config: { title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right' }, }, }); }); }, []); return null; } ``` ### Configuration Pass any [AeoConfig](/reference/configuration/) options in the `aeo` key: ```js export default withAeo({ aeo: { title: 'My Site', url: 'https://mysite.com', generators: { robotsTxt: true, llmsTxt: true, schema: true, }, widget: { enabled: true, position: 'bottom-right', }, }, }); ``` --- # Nuxt Source: docs/frameworks/nuxt.mdx > Use aeo.js with Nuxt 3. import { Steps } from '@astrojs/starlight/components'; ### Setup <Steps> 1. Install the package: ```bash npm install aeo.js ``` 2. Add the module to your Nuxt config: ```ts // nuxt.config.ts export default defineNuxtConfig({ modules: ['aeo.js/nuxt'], aeo: { title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }, }); ``` </Steps> ### How it works The Nuxt module: - Scans your `pages/` directory for routes - Generates AEO files during dev and production builds - Scans pre-rendered HTML from `.output/public/` for full page content - Injects the widget as a client-side Nuxt plugin - Adds `<link>` and `<meta>` tags for AEO discoverability ### Configuration Pass any [AeoConfig](/reference/configuration/) options in the `aeo` key: ```ts export default defineNuxtConfig({ modules: ['aeo.js/nuxt'], aeo: { title: 'My Site', url: 'https://mysite.com', generators: { robotsTxt: true, llmsTxt: true, rawMarkdown: true, }, widget: { enabled: true, position: 'bottom-left', }, }, }); ``` --- # Vanilla JS / Static HTML Source: docs/frameworks/vanilla.mdx > Use aeo.js with a plain HTML site, hand-rolled JS, or any static-site generator — no framework required. import { Tabs, TabItem, Aside } from '@astrojs/starlight/components'; aeo.js works on any project that produces static HTML. Use the CLI directly — no plugin, no module, no framework. ### Quick Start <Tabs> <TabItem label="Zero-install (npx)"> ```bash npx aeo.js generate --url https://mysite.com --title "My Site" --out public ``` </TabItem> <TabItem label="Installed"> ```bash npm install --save-dev aeo.js npx aeo.js generate --url https://mysite.com --title "My Site" --out public ``` </TabItem> </Tabs> `generate` walks your output directory, extracts page content, and emits `robots.txt`, `llms.txt`, `sitemap.xml`, `ai-index.json`, and `schema.json` next to your HTML. <Aside type="caution"> The standalone CLI configures itself from **flags only** — it does not load `aeo.config.{ts,js}`. Pass `--url` / `--title` / `--out` on the command line, or call the package's API programmatically (see "Calling the API directly" below) to access richer options like `contentDir` and `pages`. </Aside> ### How aeo.js Discovers Your Pages | Source | How to set | Use when | |---|---|---| | **Built HTML in `outDir`** | `--out public` (CLI) | You have a built static site with `*.html` files | | **`contentDir`** | programmatic only — see below | You have handwritten `.md` / `.mdx` files | | **`pages` array** | programmatic only — see below | Explicit control for runtime-only routes | The CLI exposes `--out` for `outDir`. For the richer options (`contentDir`, `pages`), call the package's API directly: ```js // scripts/aeo.mjs import { generateAEOFiles, resolveConfig } from 'aeo.js'; await generateAEOFiles(resolveConfig({ title: 'My Site', url: 'https://mysite.com', contentDir: 'content', outDir: 'public', pages: [{ pathname: '/', title: 'Home' }], })); ``` ### Common Setups #### Hand-rolled HTML site ```jsonc // package.json { "scripts": { "build:aeo": "aeo.js generate --url https://mysite.com --title \"My Site\" --out ." } } ``` #### Eleventy / Hugo / Jekyll ```jsonc // package.json { "scripts": { "build": "eleventy", "postbuild": "aeo.js generate --url https://mysite.com --title \"My Site\" --out _site" } } ``` For Hugo use `--out public`; for Jekyll `--out _site`. The `postbuild` script runs automatically after `npm run build`. #### Markdown blog (no framework) The CLI's `--out` flag covers built HTML; to also pull `.md` front-matter and bodies from a `contentDir`, use the programmatic API: ```js // scripts/aeo.mjs import { generateAEOFiles, resolveConfig } from 'aeo.js'; await generateAEOFiles(resolveConfig({ title: 'My Blog', url: 'https://myblog.dev', contentDir: 'content', // pull post bodies from here outDir: 'public', // write generated files here })); ``` ```jsonc // package.json { "scripts": { "build:aeo": "node scripts/aeo.mjs" } } ``` ### Adding the Widget ```html <script type="module"> import { AeoWidget } from 'https://esm.sh/aeo.js/widget'; new AeoWidget({ config: { title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right', size: 'small' }, }, }); </script> ``` Or install and bundle locally with `import { AeoWidget } from 'aeo.js/widget'`. ### CI Integration ```yaml - run: npx aeo.js check --json | tee audit.json - run: | SCORE=$(jq '.audit.score' audit.json) [ "$SCORE" -ge 70 ] || { echo "GEO score $SCORE below 70"; exit 1; } ``` <Aside> Full walkthrough with deployment recipes (Vercel, Netlify, Cloudflare, GitHub Pages) is in the [Vanilla Guide on GitHub](https://github.com/multivmlabs/aeo.js/blob/main/docs/vanilla.md). </Aside> ### Further Reading - [CLI Reference](/features/cli/) — every command, every flag - [JSON-LD Recipes](/features/json-ld/) — FAQ, HowTo, Product, Article, Recipe, Event - [Configuration Reference](/reference/configuration/) --- # Vite Source: docs/frameworks/vite.mdx > Use aeo.js with Vite (React, Vue, Svelte, etc.). import { Steps } from '@astrojs/starlight/components'; ### Setup <Steps> 1. Install the package: ```bash npm install aeo.js ``` 2. Add the plugin to your Vite config: ```js // vite.config.ts import { defineConfig } from 'vite'; import { aeoVitePlugin } from 'aeo.js/vite'; export default defineConfig({ plugins: [ aeoVitePlugin({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }), ], }); ``` </Steps> ### How it works The Vite plugin: - Generates AEO files on both `vite dev` and `vite build` - Injects the Human/AI widget automatically via HTML transform - Serves dynamic `.md` files during development (extracts content from your running app) - Detects SPA shells and falls back to client-side DOM extraction - Works with React, Vue, Svelte, or any Vite-based framework ### Configuration Pass any [AeoConfig](/reference/configuration/) options to the plugin: ```js aeoVitePlugin({ title: 'My Site', url: 'https://mysite.com', widget: { position: 'top-right', theme: { background: 'rgba(0, 0, 0, 0.85)', accent: '#f59e0b', }, }, }); ``` --- # Webpack Source: docs/frameworks/webpack.mdx > Use aeo.js with Webpack. import { Steps } from '@astrojs/starlight/components'; ### Setup <Steps> 1. Install the package: ```bash npm install aeo.js ``` 2. Add the plugin to your Webpack config: ```js // webpack.config.js const { AeoWebpackPlugin } = require('aeo.js/webpack'); module.exports = { plugins: [ new AeoWebpackPlugin({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }), ], }; ``` </Steps> ### How it works The Webpack plugin: - Runs during the `emit` phase of the Webpack compilation - Generates all AEO files in your output directory - Injects the widget into your HTML entry point ### Configuration Pass any [AeoConfig](/reference/configuration/) options to the plugin: ```js new AeoWebpackPlugin({ title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right', }, }); ``` --- # Installation Source: docs/getting-started/installation.mdx > Install aeo.js in your project. import { Tabs, TabItem } from '@astrojs/starlight/components'; ### Install the package <Tabs> <TabItem label="npm"> ```bash npm install aeo.js ``` </TabItem> <TabItem label="pnpm"> ```bash pnpm add aeo.js ``` </TabItem> <TabItem label="yarn"> ```bash yarn add aeo.js ``` </TabItem> </Tabs> ### Or use the CLI directly No installation needed — run it with `npx`: ```bash npx aeo.js generate ``` ### Requirements - **Node.js** 18 or later - A framework with a build step that outputs HTML (or use the CLI for any static site) ### Next steps Head to [Quick Start](/getting-started/quick-start/) to add aeo.js to your project, or jump to your framework's guide: - [Astro](/frameworks/astro/) - [Next.js](/frameworks/nextjs/) - [Vite](/frameworks/vite/) - [Nuxt](/frameworks/nuxt/) - [Angular](/frameworks/angular/) - [Webpack](/frameworks/webpack/) --- # Introduction Source: docs/getting-started/introduction.mdx > What is aeo.js and why you need Answer Engine Optimization. import { Aside } from '@astrojs/starlight/components'; ![aeo.js in action](/example.webp) ### What is Answer Engine Optimization? Answer Engine Optimization (AEO) is the practice of making your website discoverable and citable by AI-powered answer engines like **ChatGPT**, **Claude**, **Perplexity**, and **SearchGPT**. Unlike traditional SEO which focuses on search engine result pages (SERPs), AEO ensures your content is understood and referenced by Large Language Models (LLMs) when they generate answers. ### Why aeo.js? AI crawlers and LLMs look for specific files and formats that most websites don't provide: - **`llms.txt`** — A concise summary of your site written for LLMs - **`llms-full.txt`** — Full content concatenated for deep ingestion - **`ai-index.json`** — Structured content optimized for RAG pipelines - **`docs.json`** — Documentation manifest for content discovery - **Raw Markdown** — Per-page `.md` files for clean content extraction **aeo.js** generates all of these automatically from your existing pages — no manual work required. ### How it works 1. **Install** the package and add the plugin for your framework 2. **Build** your site as usual 3. **aeo.js** scans your output, extracts content, and generates all AEO files 4. The optional **widget** lets visitors toggle between human and AI views of your pages ### Scope: what aeo.js does and doesn't influence AEO is the **on-site** half of being discoverable by AI engines — there's an off-site half that aeo.js cannot reach. Setting expectations upfront so you can plan a full strategy: <Aside type="note" title="What aeo.js does well"> Improves machine-readable access to **your own site**: - generates `llms.txt`, `llms-full.txt`, `ai-index.json`, raw markdown copies, JSON-LD schema, and a sitemap - structures content so AI crawlers can fetch, parse, and quote it - audits and scores your page-level citability so you know where to improve </Aside> <Aside type="caution" title="What aeo.js cannot influence"> Off-site signals that AI engines also weigh: - **third-party mentions and reviews** of your product across the web - **inbound links** and how reputable the linking domains are - **community discussions** (Reddit, Hacker News, X, niche forums) and how often you're cited there - **model training data** — what an LLM "already knows" about you from its pre-training cutoff - **freshness signals** outside your control (independent news, blog roundups, podcasts) </Aside> Think of aeo.js as a strong foundation — necessary but not sufficient. For full AEO coverage, pair it with the off-site work above: PR, community engagement, and being mentioned where your customers research. ### Supported Frameworks | Framework | Import | |-----------|--------| | Astro | `aeo.js/astro` | | Next.js | `aeo.js/next` | | Vite (React, Vue, Svelte) | `aeo.js/vite` | | Nuxt | `aeo.js/nuxt` | | Angular | `aeo.js/angular` | | Webpack | `aeo.js/webpack` | | Any (CLI) | `npx aeo.js generate` | --- # Quick Start Source: docs/getting-started/quick-start.mdx > Get aeo.js running in under 2 minutes. import { Tabs, TabItem, Steps } from '@astrojs/starlight/components'; The fastest way to add AEO to your site depends on your framework. ### Astro <Steps> 1. Install the package: ```bash npm install aeo.js ``` 2. Add the integration to your Astro config: ```js // astro.config.mjs import { defineConfig } from 'astro/config'; import { aeoAstroIntegration } from 'aeo.js/astro'; export default defineConfig({ site: 'https://mysite.com', integrations: [ aeoAstroIntegration({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }), ], }); ``` 3. Build your site — all AEO files are generated automatically. </Steps> ### Next.js <Steps> 1. Install the package: ```bash npm install aeo.js ``` 2. Wrap your Next.js config: ```js // next.config.mjs import { withAeo } from 'aeo.js/next'; export default withAeo({ aeo: { title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }, }); ``` 3. Add the post-build step to `package.json`: ```json { "scripts": { "postbuild": "node -e \"import('aeo.js/next').then(m => m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\"" } } ``` </Steps> ### Vite <Steps> 1. Install the package: ```bash npm install aeo.js ``` 2. Add the plugin to your Vite config: ```js // vite.config.ts import { defineConfig } from 'vite'; import { aeoVitePlugin } from 'aeo.js/vite'; export default defineConfig({ plugins: [ aeoVitePlugin({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }), ], }); ``` </Steps> ### CLI (any site) No framework integration needed: ```bash npx aeo.js generate --url https://mysite.com --title "My Site" ``` See [CLI docs](/features/cli/) for all commands and options. --- # aeo.js Source: docs/index.mdx > Answer Engine Optimization for the modern web. Make your site discoverable by AI crawlers and LLMs. import { Tabs, TabItem } from '@astrojs/starlight/components'; import StickyNav from '../../components/StickyNav.astro'; import HomepageContributors from '../../components/HomepageContributors.astro'; <StickyNav /> ### Quick Start ```bash npm install aeo.js ``` <Tabs> <TabItem label="Astro"> ```js // astro.config.mjs import { defineConfig } from 'astro/config'; import { aeoAstroIntegration } from 'aeo.js/astro'; export default defineConfig({ site: 'https://mysite.com', integrations: [ aeoAstroIntegration({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }), ], }); ``` </TabItem> <TabItem label="Next.js"> ```js // next.config.mjs import { withAeo } from 'aeo.js/next'; export default withAeo({ aeo: { title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }, }); ``` Add the post-build step to `package.json`: ```json { "scripts": { "postbuild": "node -e \"import('aeo.js/next').then(m => m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\"" } } ``` </TabItem> <TabItem label="Vite"> ```js // vite.config.ts import { defineConfig } from 'vite'; import { aeoVitePlugin } from 'aeo.js/vite'; export default defineConfig({ plugins: [ aeoVitePlugin({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }), ], }); ``` </TabItem> <TabItem label="Nuxt"> ```ts // nuxt.config.ts export default defineNuxtConfig({ modules: ['aeo.js/nuxt'], aeo: { title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }, }); ``` </TabItem> <TabItem label="Angular"> Add a post-build step to `package.json`: ```json { "scripts": { "postbuild": "node -e \"import('aeo.js/angular').then(m => m.postBuild({ title: 'My App', url: 'https://myapp.com' }))\"" } } ``` Or generate programmatically: ```ts import { generate } from 'aeo.js/angular'; await generate({ title: 'My App', url: 'https://myapp.com' }); ``` </TabItem> <TabItem label="Webpack"> ```js // webpack.config.js const { AeoWebpackPlugin } = require('aeo.js/webpack'); module.exports = { plugins: [ new AeoWebpackPlugin({ title: 'My Site', description: 'A site optimized for AI discovery', url: 'https://mysite.com', }), ], }; ``` </TabItem> <TabItem label="CLI"> No framework needed — run standalone: ```bash # Generate all AEO files npx aeo.js generate --url https://mysite.com --title "My Site" # Scaffold a config file npx aeo.js init # Check your setup npx aeo.js check ``` </TabItem> </Tabs> ### What is AEO? Answer Engine Optimization (AEO) is the practice of making your website discoverable and citable by AI-powered answer engines like ChatGPT, Claude, Perplexity, and SearchGPT. **aeo.js** auto-generates the files these engines look for and provides a drop-in widget that shows visitors how your site appears to AI. First-class support for Astro, Next.js, Vite, Nuxt, Angular, and Webpack — or run standalone via CLI. ### Why AEO matters <div class="why-aeo-grid"> <div class="why-card"> <div class="why-stat">58%</div> <div class="why-label">of searches</div> <div class="why-desc">end without a click — AI gives the answer directly</div> </div> <div class="why-card"> <div class="why-stat">40%</div> <div class="why-label">of Gen Z</div> <div class="why-desc">prefer AI assistants over traditional search engines</div> </div> <div class="why-card"> <div class="why-stat">97%</div> <div class="why-label">of sites</div> <div class="why-desc">have no llms.txt or structured data for AI crawlers</div> </div> <div class="why-card"> <div class="why-stat">1 min</div> <div class="why-label">to set up</div> <div class="why-desc">aeo.js generates robots.txt, llms.txt, schema & more</div> </div> </div> If your site isn't optimized for AI engines, you're invisible to a growing share of users who never open a search results page. AEO is the new SEO. ### Widget The Human/AI widget lets visitors toggle between the normal page and its AI-readable markdown version. Framework plugins inject it automatically — for Next.js or manual setups: ```tsx 'use client'; import { useEffect } from 'react'; export function AeoWidgetLoader() { useEffect(() => { import('aeo.js/widget').then(({ AeoWidget }) => { new AeoWidget({ config: { title: 'My Site', url: 'https://mysite.com', widget: { enabled: true, position: 'bottom-right' }, }, }); }); }, []); return null; } ``` React and Vue wrapper components are also available: <Tabs> <TabItem label="React"> ```tsx import { AeoReactWidget } from 'aeo.js/react'; <AeoReactWidget config={{ title: 'My Site', url: 'https://mysite.com' }} /> ``` </TabItem> <TabItem label="Vue"> ```vue <script setup> import { AeoVueWidget } from 'aeo.js/vue'; </script> <template> <AeoVueWidget :config="{ title: 'My Site', url: 'https://mysite.com' }" /> </template> ``` </TabItem> </Tabs> ### Configuration All frameworks use the same config shape — [see full reference](/reference/configuration/): ```ts import { defineConfig } from 'aeo.js'; export default defineConfig({ title: 'My Site', url: 'https://mysite.com', description: 'A site optimized for AI discovery', generators: { robotsTxt: true, llmsTxt: true, llmsFullTxt: true, rawMarkdown: true, sitemap: true, aiIndex: true, schema: true, }, schema: { enabled: true, organization: { name: 'My Company', url: 'https://mysite.com' }, defaultType: 'WebPage', }, og: { enabled: true, image: 'https://mysite.com/og.png', twitterHandle: '@mycompany', }, widget: { enabled: true, position: 'bottom-right', theme: { accent: '#4ADE80', badge: '#4ADE80' }, }, }); ``` ### Generated Files After building, your output directory contains: ``` public/ ├── robots.txt # AI-crawler directives ├── llms.txt # Short LLM-readable summary ├── llms-full.txt # Full content for LLMs ├── sitemap.xml # Standard sitemap ├── docs.json # Documentation manifest ├── ai-index.json # AI content index ├── index.md # Markdown for / └── about.md # Markdown for /about ``` ### Checker <div class="aeo-checker-widget" style={{marginTop: '1rem', marginBottom: '0.5rem'}}> <form id="aeo-check-form" class="aeo-checker-input-wrap" action="https://check.aeojs.org" method="GET"> <input type="text" name="q" class="aeo-checker-input" placeholder="Enter your website URL…" required /> <button type="submit" class="aeo-checker-btn"> Scan <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg> </button> </form> <p style={{textAlign: 'center', fontSize: '0.8rem', color: 'rgba(255,255,255,0.3)', marginTop: '0.75rem'}}>Free — no signup required. Powered by <a href="https://check.aeojs.org" style={{color: 'rgba(255,255,255,0.5)', textDecoration: 'underline', textUnderlineOffset: '2px'}}>AEO Checker</a></p> </div> <HomepageContributors /> --- # API Reference Source: docs/reference/api.mdx > Programmatic API for aeo.js. ### Core #### `defineConfig(config)` Type-safe configuration helper: ```ts import { defineConfig } from 'aeo.js'; export default defineConfig({ title: 'My Site', url: 'https://mysite.com', }); ``` #### `generateAll(config)` Generate all AEO files programmatically: ```ts import { generateAll } from 'aeo.js'; await generateAll({ title: 'My Site', url: 'https://mysite.com', outDir: 'dist', }); ``` #### `resolveConfig(config)` Resolve a partial config into a fully resolved config with defaults: ```ts import { resolveConfig } from 'aeo.js'; const resolved = resolveConfig({ title: 'My Site' }); // All fields now have defaults ``` The examples below use `resolvedConfig` for a config object returned by `resolveConfig`. #### `validateConfig(config)` Validate a config object and return any errors: ```ts import { validateConfig } from 'aeo.js'; const errors = validateConfig(config); ``` #### `detectFramework()` Auto-detect the framework used in the current project: ```ts import { detectFramework } from 'aeo.js'; const info = detectFramework(); // { framework: 'next', contentDir: 'pages', outDir: '.next' } ``` ### HTML Extraction #### `htmlToMarkdown(html, pagePath, config)` Convert HTML to clean markdown: ```ts import { htmlToMarkdown } from 'aeo.js'; const md = htmlToMarkdown( '<html><head><title>Hello

World

', '/', { url: 'https://mysite.com' } ); // Returns a markdown document with YAML frontmatter ``` #### `extractTextFromHtml(html)` Extract plain text from HTML: ```ts import { extractTextFromHtml } from 'aeo.js'; const text = extractTextFromHtml('

Hello world

'); ``` #### `extractTitle(html)` / `extractDescription(html)` Extract the title or meta description from an HTML document. #### `extractJsonLd(html)` Extract JSON-LD structured data from an HTML document. ### Schema #### `generateSchemaObjects(config)` Generate JSON-LD schema objects: ```ts import { generateSchemaObjects } from 'aeo.js'; const schemas = generateSchemaObjects(resolvedConfig); ``` #### `generateJsonLdScript(schemas)` Generate a `