Package Exports
- aeo.js
- aeo.js/angular
- aeo.js/astro
- aeo.js/next
- aeo.js/nuxt
- aeo.js/react
- aeo.js/vite
- aeo.js/vue
- aeo.js/webpack
- aeo.js/widget
Readme
aeo.js
Answer Engine Optimization for the modern web. Make your site discoverable by AI crawlers and LLMs.
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.
Features
llms.txt/llms-full.txt-- LLM-readable summaries of your siterobots.txt-- AI-crawler-aware robots directivessitemap.xml-- Standard sitemap generationdocs.json-- Structured documentation manifestai-index.json-- AI-optimized content index- Raw Markdown -- Per-page
.mdfiles extracted from your HTML - Human/AI Widget -- Drop-in toggle showing the AI-readable version of any page
- CLI --
npx aeo.js generateto run standalone
Supported Frameworks
| Framework | Status | Import |
|---|---|---|
| Astro | Stable | aeo.js/astro |
| Next.js | Stable | aeo.js/next |
| Vite / React | Stable | aeo.js/vite |
| Nuxt | Stable | aeo.js/nuxt |
| Angular | Stable | aeo.js/angular |
| Webpack | Stable | aeo.js/webpack |
| Any (CLI) | Stable | npx aeo.js generate |
Install
npm install aeo.jsQuick Start
Astro
// 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',
}),
],
});The widget is automatically injected and persists across View Transitions.
Next.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',
},
});After building, run the post-build step to extract content from pre-rendered pages:
{
"scripts": {
"postbuild": "node -e \"import('aeo.js/next').then(m => m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\""
}
}Vite (React, Vue, Svelte, etc.)
// 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',
}),
],
});The Vite plugin:
- Generates AEO files on
vite devandvite build - Injects the widget automatically
- Serves dynamic
.mdfiles in dev (extracts content from your running app) - Detects SPA shells and falls back to client-side DOM extraction
Nuxt
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',
},
});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
Angular
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' }))\""
}
}The Angular plugin:
- Reads
angular.jsonto 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.htmlautomatically
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' });Webpack
// 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',
}),
],
};CLI
Run aeo.js from the command line without any framework integration:
# Generate all AEO files
npx aeo.js generate
# Generate with options
npx aeo.js generate --url https://mysite.com --title "My Site" --out public
# Create a config file
npx aeo.js init
# Check your setup
npx aeo.js checkCommands
| Command | Description |
|---|---|
generate |
Generate all AEO files (robots.txt, llms.txt, sitemap.xml, etc.) |
init |
Create an aeo.config.ts configuration file |
check |
Validate your AEO setup and show what would be generated |
Options
| Flag | Description |
|---|---|
--out <dir> |
Output directory (default: auto-detected) |
--url <url> |
Site URL |
--title <title> |
Site title |
--no-widget |
Disable widget generation |
--help, -h |
Show help |
--version, -v |
Show version |
Configuration
All framework plugins accept the same config object. You can also use defineConfig for standalone configs:
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, // robots.txt
llmsTxt: true, // llms.txt
llmsFullTxt: true, // llms-full.txt
rawMarkdown: true, // Per-page .md files
manifest: true, // docs.json
sitemap: true, // sitemap.xml
aiIndex: true, // ai-index.json
},
// Customize robots.txt
robots: {
allow: ['/'],
disallow: ['/admin'],
crawlDelay: 0,
},
// Widget configuration
widget: {
enabled: true,
position: 'bottom-right', // 'bottom-left' | 'top-right' | 'top-left'
humanLabel: 'Human',
aiLabel: 'AI',
showBadge: true,
theme: {
background: 'rgba(18, 18, 24, 0.9)',
text: '#C0C0C5',
accent: '#E8E8EA',
badge: '#4ADE80',
},
},
});Widget
The Human/AI widget is a floating toggle that lets visitors switch between the normal page and its AI-readable markdown version. Framework plugins (Astro, Vite, Nuxt, Angular) inject it automatically. For Next.js or manual setups:
// 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;
}When a visitor clicks AI, the widget:
- Fetches the
.mdfile for the current page - Falls back to extracting markdown from the live DOM if no
.mdexists - Displays the markdown in a slide-out panel
- Offers copy-to-clipboard and download actions
Generated Files
After building, your output directory will contain:
public/
robots.txt # AI-crawler-aware 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-optimized content index
index.md # Markdown for /
about.md # Markdown for /about
... # One .md per discovered pageLicense
MIT