diff --git a/docs/README.md b/docs/README.md
new file mode 100755
index 0000000..642402b
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,431 @@
+# Framework Integration Guides
+
+Comprehensive guides for integrating aeo.js with popular web frameworks to optimize your site for AI search engines like ChatGPT, Claude, Perplexity, and more.
+
+## Overview
+
+aeo.js (Answer Engine Optimization) helps make your website discoverable and understandable by AI-powered search engines. These guides provide step-by-step instructions for integrating aeo.js with your preferred framework.
+
+## What is AEO?
+
+Answer Engine Optimization (AEO) is the process of optimizing your website to be better understood and indexed by AI search engines. Unlike traditional SEO which focuses on keyword rankings, AEO focuses on:
+
+- **Structured content** - Making your content machine-readable
+- **Semantic markup** - Using JSON-LD and schema.org
+- **AI discovery files** - Generating llms.txt, robots.txt, sitemaps
+- **Context signals** - Providing clear page descriptions and metadata
+
+## Supported Frameworks
+
+aeo.js provides native integrations for the following frameworks:
+
+| Framework | Guide | Integration Type | Status |
+|-----------|-------|------------------|--------|
+| Next.js | [nextjs.md](./nextjs.md) | Plugin + Middleware | ✅ Stable |
+| Astro | [astro.md](./astro.md) | Native Integration | ✅ Stable |
+| Nuxt | [nuxt.md](./nuxt.md) | Module | ✅ Stable |
+| Vite | [vite.md](./vite.md) | Plugin | ✅ Stable |
+| Angular | [angular.md](./angular.md) | Post-build | ✅ Stable |
+| Webpack | [webpack.md](./webpack.md) | Plugin | ✅ Stable |
+
+## Quick Start
+
+Choose your framework:
+
+### Next.js
+```bash
+npm install aeo.js
+```
+
+```js
+// next.config.mjs
+import { withAeo } from 'aeo.js/next';
+
+export default withAeo({
+ aeo: {
+ title: 'My Site',
+ description: 'Optimized for AI discovery',
+ url: 'https://mysite.com',
+ },
+});
+```
+
+[→ Full Next.js Guide](./nextjs.md)
+
+### Astro
+```bash
+npm install aeo.js
+```
+
+```js
+// astro.config.mjs
+import { aeoAstroIntegration } from 'aeo.js/astro';
+
+export default defineConfig({
+ integrations: [
+ aeoAstroIntegration({
+ title: 'My Site',
+ url: 'https://mysite.com',
+ }),
+ ],
+});
+```
+
+[→ Full Astro Guide](./astro.md)
+
+### Nuxt
+```bash
+npm install aeo.js
+```
+
+```ts
+// nuxt.config.ts
+export default defineNuxtConfig({
+ modules: ['aeo.js/nuxt'],
+ aeo: {
+ title: 'My Site',
+ url: 'https://mysite.com',
+ },
+});
+```
+
+[→ Full Nuxt Guide](./nuxt.md)
+
+### Vite
+```bash
+npm install aeo.js
+```
+
+```js
+// vite.config.ts
+import { aeoVitePlugin } from 'aeo.js/vite';
+
+export default defineConfig({
+ plugins: [
+ aeoVitePlugin({
+ title: 'My Site',
+ url: 'https://mysite.com',
+ }),
+ ],
+});
+```
+
+[→ Full Vite Guide](./vite.md)
+
+### Angular
+```bash
+npm install aeo.js
+```
+
+```json
+{
+ "scripts": {
+ "build": "ng build",
+ "postbuild": "node -e \"import('aeo.js/angular').then(m => m.postBuild({ title: 'My App', url: 'https://myapp.com' }))\""
+ }
+}
+```
+
+[→ Full Angular Guide](./angular.md)
+
+### Webpack
+```bash
+npm install aeo.js
+```
+
+```js
+// webpack.config.js
+const { AeoWebpackPlugin } = require('aeo.js/webpack');
+
+module.exports = {
+ plugins: [
+ new AeoWebpackPlugin({
+ title: 'My Site',
+ url: 'https://mysite.com',
+ }),
+ ],
+};
+```
+
+[→ Full Webpack Guide](./webpack.md)
+
+## What Gets Generated?
+
+When you integrate aeo.js, it automatically generates:
+
+### 1. llms.txt
+A structured file that AI search engines use to understand your site's content and structure.
+
+```
+# My Site
+
+> Optimized for AI discovery
+
+## Site Information
+- URL: https://mysite.com
+- Description: A comprehensive resource for...
+- Last Updated: 2026-05-09
+
+## Pages
+- /about: About our company and mission
+- /blog: Technical articles and tutorials
+- /products: Our product offerings
+```
+
+### 2. Enhanced robots.txt
+```
+User-agent: *
+Allow: /
+
+User-agent: GPTBot
+Allow: /
+
+User-agent: Claude-Web
+Allow: /
+
+Sitemap: https://mysite.com/sitemap.xml
+```
+
+### 3. XML Sitemap
+```xml
+
+
+
+ https://mysite.com/
+ 2026-05-09
+ 1.0
+
+
+
+```
+
+### 4. JSON-LD Structured Data
+Automatically injects schema.org structured data into your pages:
+
+```json
+{
+ "@context": "https://schema.org",
+ "@type": "WebSite",
+ "name": "My Site",
+ "url": "https://mysite.com",
+ "description": "Optimized for AI discovery"
+}
+```
+
+## Configuration Options
+
+All framework integrations accept the same `AeoConfig` shape:
+
+> All fields are optional in TypeScript, but **`url` should always be set** for production. Omitting it causes `sitemap.xml`, `llms.txt`, and JSON-LD to fall back to `https://example.com` (`validateConfig` will also warn).
+
+```typescript
+type AeoConfig = {
+ // Strongly recommended
+ title?: string; // Your site title (defaults to "My Site")
+ url?: string; // Your production URL (defaults to "https://example.com")
+
+ // Optional
+ description?: string; // Site description
+ contentDir?: string; // Directory of handwritten markdown
+ outDir?: string; // Where to write AEO files
+ pages?: PageEntry[]; // Explicit pages (mostly auto-discovered by plugins)
+
+ // Toggle individual generators (all default true)
+ generators?: {
+ robotsTxt?: boolean;
+ llmsTxt?: boolean;
+ llmsFullTxt?: boolean;
+ rawMarkdown?: boolean;
+ manifest?: boolean;
+ sitemap?: boolean;
+ aiIndex?: boolean;
+ schema?: boolean;
+ };
+
+ // robots.txt directives
+ robots?: {
+ allow?: string[]; // Default: ['/']
+ disallow?: string[];
+ crawlDelay?: number; // Seconds
+ sitemap?: string;
+ };
+
+ // JSON-LD structured data
+ schema?: {
+ enabled?: boolean;
+ organization?: {
+ name?: string;
+ url?: string;
+ logo?: string;
+ sameAs?: string[];
+ };
+ defaultType?: 'Article' | 'WebPage';
+ };
+
+ // Open Graph tags
+ og?: {
+ enabled?: boolean;
+ image?: string;
+ twitterHandle?: string;
+ type?: 'website' | 'article';
+ };
+
+ // The Human/AI widget injected into pages
+ widget?: {
+ enabled?: boolean;
+ position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
+ size?: 'default' | 'small' | 'icon-only';
+ theme?: { background?: string; text?: string; accent?: string; badge?: string };
+ humanLabel?: string;
+ aiLabel?: string;
+ showBadge?: boolean;
+ };
+
+ // ai-index.json chunking & keyword extraction
+ aiIndex?: {
+ maxChunkLength?: number; // Default: 2000 (soft limit; splits on paragraph)
+ maxKeywords?: number; // Default: 10
+ };
+};
+
+type PageEntry = {
+ pathname: string; // e.g. '/about'
+ title?: string;
+ description?: string;
+ content?: string;
+};
+```
+
+> See [aeojs.org/reference/configuration](https://aeojs.org/reference/configuration/) for the full reference.
+
+## Common Use Cases
+
+### Blog / Content Site
+Perfect for making your articles discoverable by AI assistants:
+
+```js
+{
+ title: 'Tech Blog',
+ description: 'In-depth technical tutorials and guides',
+ schema: {
+ enabled: true, // Generates Article schema for FAQ/HowTo patterns
+ organization: { name: 'Tech Blog', url: 'https://techblog.com' },
+ },
+}
+```
+
+### Documentation Site
+Optimize technical documentation for AI-powered search:
+
+```js
+{
+ title: 'API Documentation',
+ description: 'Complete API reference and guides',
+ pages: [
+ { pathname: '/api', title: 'API Reference', description: 'Full endpoint reference' },
+ { pathname: '/guides', title: 'Getting Started Guides' },
+ ],
+}
+```
+
+### E-commerce Site
+Help AI understand your product catalog. Use `robots.disallow` to block crawler access to private routes (it does not remove them from generated AEO files; for those, scope `contentDir` instead):
+
+```js
+{
+ title: 'Online Store',
+ description: 'Quality products delivered fast',
+ robots: {
+ disallow: ['/checkout', '/account', '/api'],
+ },
+ schema: {
+ enabled: true,
+ organization: { name: 'My Store', url: 'https://mystore.com' },
+ },
+}
+```
+
+### SaaS Product
+Optimize your marketing site and product pages:
+
+```js
+{
+ title: 'My SaaS Product',
+ description: 'The best tool for...',
+ pages: [
+ { pathname: '/', title: 'Home' },
+ { pathname: '/features', title: 'Features' },
+ { pathname: '/pricing', title: 'Pricing' },
+ { pathname: '/docs', title: 'Documentation' },
+ ],
+}
+```
+
+## Best Practices
+
+1. **Set accurate metadata** - Provide clear, descriptive titles and descriptions
+2. **Use semantic HTML** - Structure your content with proper headings
+3. **Include alt text** - Describe images for better AI understanding
+4. **Add structured data** - Use JSON-LD for rich content markup
+5. **Keep content fresh** - Update llms.txt when content changes
+6. **Test with AI** - Ask ChatGPT or Claude about your site
+7. **Monitor performance** - Track AI referrals in analytics
+
+## Troubleshooting
+
+### Files not generating?
+
+Check that:
+- Build process completes successfully
+- Output directory has write permissions
+- Configuration is valid
+
+### AI not finding my site?
+
+Ensure:
+- llms.txt is publicly accessible at `/llms.txt`
+- robots.txt allows AI crawlers
+- Sitemap is linked in robots.txt
+- DNS and SSL are properly configured
+
+### Framework-specific issues?
+
+See the detailed framework guides:
+- [Next.js Troubleshooting](./nextjs.md#troubleshooting)
+- [Astro Troubleshooting](./astro.md#troubleshooting)
+- [Nuxt Troubleshooting](./nuxt.md#troubleshooting)
+- [Vite Troubleshooting](./vite.md#troubleshooting)
+
+## Migration Guides
+
+### From Manual AEO
+If you've been manually creating llms.txt and robots.txt:
+
+1. Remove manual files from your public directory
+2. Install and configure aeo.js
+3. Run build to generate files automatically
+4. Verify generated files match your requirements
+5. Commit the configuration, delete manual files
+
+### From Other AEO Tools
+Coming soon - guides for migrating from other AEO solutions.
+
+## Getting Help
+
+- **Issues**: [GitHub Issues](https://github.com/multivmlabs/aeo.js/issues)
+- **Discussions**: [GitHub Discussions](https://github.com/multivmlabs/aeo.js/discussions)
+- **Updates**: Follow [@multivmlabs](https://twitter.com/multivmlabs)
+
+## Contributing
+
+Found a better way to configure aeo.js for your framework? Have an example to share?
+
+We welcome contributions! See the main [CONTRIBUTING.md](../CONTRIBUTING.md) for guidelines.
+
+## License
+
+MIT - See [LICENSE](../LICENSE) for details.
+
+---
+
+**Ready to optimize your site for AI discovery? Choose your framework guide above and get started!**
diff --git a/docs/angular.md b/docs/angular.md
new file mode 100644
index 0000000..bed46db
--- /dev/null
+++ b/docs/angular.md
@@ -0,0 +1,280 @@
+# Angular Integration Guide
+
+Make your Angular site discoverable by AI search engines like ChatGPT, Claude, Perplexity, and SearchGPT.
+
+## Prerequisites
+
+- Node.js 18+
+- An Angular 15+ project (works with both standalone components and `NgModule` projects)
+- TypeScript is the default for Angular
+
+## Installation
+
+```bash
+npm install aeo.js
+# or
+yarn add aeo.js
+# or
+pnpm add aeo.js
+```
+
+## Quick Start
+
+The Angular integration is a **post-build** step: after `ng build` produces your `dist/` output, `aeo.js/angular` scans the emitted HTML and writes AEO files alongside them.
+
+### Step 1: Add the post-build script
+
+```json
+{
+ "scripts": {
+ "build": "ng build",
+ "postbuild": "node -e \"import('aeo.js/angular').then(m => m.postBuild({ title: 'My App', url: 'https://myapp.com' }))\""
+ }
+}
+```
+
+npm automatically runs `postbuild` after `build`, so a single `npm run build` produces the Angular bundle **and** the AEO files.
+
+### Step 2: Build and verify
+
+```bash
+npm run build
+```
+
+You should now have these files inside your Angular `outputPath` (typically `dist//browser` for Angular 17+):
+
+- `robots.txt` — AI crawler directives
+- `llms.txt` — short summary for LLMs
+- `llms-full.txt` — full content dump
+- `sitemap.xml` — sitemap
+- `ai-index.json` — chunked content for embedding
+- `docs.json` — site manifest
+- `schema.json` — JSON-LD structured data (when `schema.enabled`)
+- Per-page `.md` files (when `generators.rawMarkdown` is enabled)
+
+## Configuration
+
+### Basic Configuration
+
+`postBuild` and `generate` accept the standard `AeoConfig`. The minimum useful shape:
+
+```typescript
+type AeoConfig = {
+ title?: string; // Strongly recommended (defaults to "My Site")
+ url?: string; // Strongly recommended (your production URL)
+ description?: string; // Recommended
+ outDir?: string; // Output directory (defaults to detected Angular dist)
+};
+```
+
+> Although `title` and `url` are optional in the type, omitting `url` causes `sitemap.xml`, `llms.txt`, and JSON-LD to fall back to `https://example.com`. Always set it for production builds. See [README.md](./README.md#configuration-options) for the full reference.
+
+### Advanced Configuration
+
+```json
+{
+ "scripts": {
+ "postbuild": "node ./scripts/aeo.mjs"
+ }
+}
+```
+
+```js
+// scripts/aeo.mjs
+import { postBuild } from 'aeo.js/angular';
+
+await postBuild({
+ title: 'My App',
+ description: 'An Angular app optimized for AI discovery',
+ url: 'https://myapp.com',
+
+ generators: {
+ robotsTxt: true,
+ llmsTxt: true,
+ llmsFullTxt: true,
+ sitemap: true,
+ aiIndex: true,
+ schema: true,
+ rawMarkdown: true,
+ },
+
+ schema: {
+ enabled: true,
+ organization: {
+ name: 'My Company',
+ url: 'https://myapp.com',
+ },
+ },
+
+ aiIndex: {
+ maxChunkLength: 2000,
+ maxKeywords: 10,
+ },
+});
+```
+
+### `postBuild` vs `generate`
+
+| Function | Scans build HTML? | Use it when |
+|---|---|---|
+| `postBuild(config)` | ✅ Yes, plus `src/app/**/*.routes.ts` | You ran `ng build` and want AEO files generated from the actual emitted HTML |
+| `generate(config)` | ❌ No — source routes only | Build output isn't available (dev/CI scripts, route discovery only) |
+
+`postBuild` is what you want for almost everything. `generate` is the lower-level escape hatch.
+
+```js
+// scripts/aeo-source-only.mjs
+import { generate } from 'aeo.js/angular';
+
+await generate({
+ title: 'My App',
+ url: 'https://myapp.com',
+ outDir: 'dist/my-app/browser',
+});
+```
+
+### Inject the Widget
+
+The Human/AI widget is **injected by default** when `widget.enabled !== false`. The Quick Start example above will already inject it into `index.html`. To customize the widget appearance:
+
+```js
+import { postBuild } from 'aeo.js/angular';
+
+await postBuild({
+ title: 'My App',
+ url: 'https://myapp.com',
+ widget: {
+ enabled: true, // default
+ position: 'bottom-right',
+ size: 'small',
+ },
+});
+```
+
+To **disable** widget injection without touching widget config elsewhere:
+
+```js
+await postBuild({
+ title: 'My App',
+ url: 'https://myapp.com',
+ injectWidget: false,
+});
+```
+
+## How It Works
+
+1. `ng build` produces a static `dist//browser` directory.
+2. The post-build hook fires; aeo.js does **two** scans:
+ - Walks the build output for `*.html` files (skipping `404.html` / `500.html`, `assets/`, `media/`). For each page it extracts the ``, meta description, and rendered text content.
+ - Walks `src/app` for `*.routes.ts` files and extracts the `path:` values declared in route configs. These add route entries to `sitemap.xml` even when no HTML was prerendered.
+3. The two sets are merged: build-output pages (with content) take priority over source-scanned routes.
+4. It writes the AEO files (`llms.txt`, `sitemap.xml`, etc.) into the same `dist` directory.
+
+For projects using **Angular Universal** (SSR) or **prerendering**, the prerendered HTML is what gets scanned — which is exactly the content AI crawlers see, so generation is accurate.
+
+## Common Setups
+
+### Angular 17+ Standalone Components
+
+No special configuration needed. The post-build script reads whatever HTML Angular emits.
+
+### Angular 16 and Below (`NgModule`)
+
+Same setup — the post-build script is build-pipeline-agnostic.
+
+### Multi-project Workspaces
+
+If your workspace has multiple Angular projects, point `outDir` at each one's output directory:
+
+```js
+// scripts/aeo-all.mjs
+import { postBuild } from 'aeo.js/angular';
+
+for (const project of ['app-a', 'app-b']) {
+ await postBuild({
+ title: `My ${project}`,
+ url: `https://${project}.example.com`,
+ outDir: `dist/${project}/browser`,
+ });
+}
+```
+
+### Angular with SSR / Prerendering
+
+Make sure the post-build script runs **after** prerendering produces the final HTML.
+
+**Angular 17+** (prerendering is configured in `angular.json` under the build target):
+
+```json
+{
+ "scripts": {
+ "build": "ng build",
+ "postbuild": "node -e \"import('aeo.js/angular').then(m => m.postBuild({ title: 'My App', url: 'https://myapp.com' }))\""
+ }
+}
+```
+
+**Angular 16 and below** (separate prerender command):
+
+```json
+{
+ "scripts": {
+ "build": "ng build && ng run my-app:prerender",
+ "postbuild": "node -e \"import('aeo.js/angular').then(m => m.postBuild({ title: 'My App', url: 'https://myapp.com' }))\""
+ }
+}
+```
+
+## Best Practices
+
+- **Set `url` to your production hostname.** It seeds `sitemap.xml`, absolute URLs in `llms.txt`, and JSON-LD.
+- **Prerender as many routes as you can.** Without prerendering, declared routes from `*.routes.ts` still appear in `sitemap.xml` — but `llms.txt` / `ai-index.json` only carry content for pages that produced HTML. Prerendered routes get the full treatment.
+- **Add `pages` for routes not declared in `*.routes.ts`.** When the auto-scan misses a route (e.g. it's defined in code, not a route config), list it explicitly:
+
+ ```js
+ await postBuild({
+ title: 'My App',
+ url: 'https://myapp.com',
+ pages: [
+ { pathname: '/', title: 'Home' },
+ { pathname: '/pricing', title: 'Pricing' },
+ ],
+ });
+ ```
+- **Verify after deploy.** Visit `https://myapp.com/llms.txt`, `/robots.txt`, and `/sitemap.xml`.
+
+## Troubleshooting
+
+### `outDir` not found
+The post-build step reads `angular.json` to detect your output directory (typically `dist//browser` for Angular 17+, `dist/` for older). If your workspace uses a non-standard layout, pass `outDir` explicitly. Top-level `await` works inside an `.mjs` file or any module with `"type": "module"`:
+
+```js
+// scripts/aeo.mjs
+import { postBuild } from 'aeo.js/angular';
+
+await postBuild({
+ title: 'My App',
+ url: 'https://myapp.com',
+ outDir: 'public',
+});
+```
+
+### `sitemap.xml` only contains the root URL
+The plugin scans **both** the build output for HTML **and** `src/app/**/*.routes.ts` for declared route paths, so an empty sitemap usually means both are empty:
+
+- No prerendering, **and** no `*.routes.ts` files found (e.g. routes defined inline in components or via `provideRouter([...])` in a non-routes file).
+- Fix one of: enable Angular prerendering, move routes into a `*.routes.ts` file, or pass `pages` explicitly (see [Add `pages` for routes not declared](#best-practices) above).
+
+### `llms.txt` text is empty
+The extractor strips scripts and boilerplate, prefers ``. If your Angular template renders everything inside a custom root without ``, AEO content extraction may produce empty pages. Wrap your routed view in ``:
+```html
+
+
+
+```
+
+## Further Reading
+
+- [aeo.js Reference Configuration](https://aeojs.org/reference/configuration/)
+- [Generated Files](https://aeojs.org/features/generated-files/)
+- [GEO Audit & Citability](https://aeojs.org/features/audit/)
diff --git a/docs/astro.md b/docs/astro.md
new file mode 100755
index 0000000..b466c13
--- /dev/null
+++ b/docs/astro.md
@@ -0,0 +1,420 @@
+# Astro Integration Guide
+
+Complete guide for integrating aeo.js with Astro to optimize your site for AI-powered search engines.
+
+## Prerequisites
+
+- **Astro**: 3.0 or higher
+- **Node.js**: 18.0 or higher
+- **Package Manager**: npm, yarn, or pnpm
+
+## Installation
+
+### Step 1: Install aeo.js
+
+```bash
+npm install aeo.js
+# or
+yarn add aeo.js
+# or
+pnpm add aeo.js
+```
+
+### Step 2: Add Integration to Astro Config
+
+```javascript
+// 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 Astro Site',
+ description: 'Built with Astro and optimized for AI discovery',
+ url: 'https://mysite.com',
+ }),
+ ],
+});
+```
+
+### Step 3: Build and Verify
+
+```bash
+npm run build
+```
+
+Check that these files were generated in your `dist` directory:
+- `dist/llms.txt`
+- `dist/robots.txt`
+- `dist/sitemap.xml`
+
+## Configuration
+
+### Basic Configuration
+
+`aeoAstroIntegration` accepts the standard `AeoConfig`. See [README.md](./README.md#configuration-options) for the full reference.
+
+### Advanced Configuration
+
+```javascript
+export default defineConfig({
+ site: 'https://mysite.com',
+ integrations: [
+ aeoAstroIntegration({
+ title: 'My Astro Site',
+ url: 'https://mysite.com',
+ description: 'Lightning-fast static site built with Astro',
+
+ // Toggle individual generators (all default true)
+ generators: {
+ llmsTxt: true,
+ llmsFullTxt: true,
+ robotsTxt: true,
+ sitemap: true,
+ aiIndex: true,
+ schema: true,
+ },
+
+ // Optional explicit page metadata (the plugin auto-discovers from src/pages/)
+ pages: [
+ { pathname: '/', title: 'Home', description: 'Welcome to our lightning-fast site' },
+ { pathname: '/blog', title: 'Blog', description: 'Latest articles' },
+ ],
+
+ // robots.txt — block crawlers from private routes
+ robots: {
+ allow: ['/'],
+ disallow: ['/admin', '/api'],
+ },
+
+ // JSON-LD structured data
+ schema: {
+ enabled: true,
+ organization: {
+ name: 'My Astro Site',
+ url: 'https://mysite.com',
+ },
+ },
+ }),
+ ],
+});
+```
+
+## Content Collections Integration
+
+Astro's content collections work seamlessly with aeo.js:
+
+```typescript
+// src/content/config.ts
+import { defineCollection, z } from 'astro:content';
+
+const blog = defineCollection({
+ schema: z.object({
+ title: z.string(),
+ description: z.string(),
+ pubDate: z.date(),
+ author: z.string(),
+ tags: z.array(z.string()),
+ }),
+});
+
+export const collections = { blog };
+```
+
+## Adding Structured Data
+
+> Astro's `set:html` directive injects the value verbatim — it does **not** escape characters that can terminate the surrounding `` (or U+2028/U+2029) would break out and execute as JavaScript. Run the payload through a serializer that escapes those characters first — the helper below is the same `serializeJsonForHtml` aeo.js uses internally ([src/core/schema.ts](https://github.com/multivmlabs/aeo.js/blob/main/src/core/schema.ts)). aeo.js's own injected JSON-LD is already safe; only your custom additions need this.
+
+```ts
+// src/lib/serialize-json-ld.ts
+export function serializeJsonForHtml(value: unknown): string {
+ return JSON.stringify(value)
+ .replace(//g, '\\u003E')
+ .replace(/&/g, '\\u0026')
+ .replace(/\u2028/g, '\\u2028')
+ .replace(/\u2029/g, '\\u2029');
+}
+```
+
+### Page-Level JSON-LD
+
+```astro
+---
+// src/pages/blog/[slug].astro
+import { getEntry } from 'astro:content';
+import { serializeJsonForHtml } from '../lib/serialize-json-ld';
+
+const { slug } = Astro.params;
+if (!slug) return Astro.redirect('/404');
+const post = await getEntry('blog', slug);
+if (!post) return Astro.redirect('/404');
+
+const schema = {
+ '@context': 'https://schema.org',
+ '@type': 'BlogPosting',
+ headline: post.data.title,
+ description: post.data.description,
+ datePublished: post.data.pubDate.toISOString(),
+ author: {
+ '@type': 'Person',
+ name: post.data.author,
+ },
+};
+---
+
+
+
+ {post.data.title}
+
+
+
+
+
+ {post.data.title}
+
+
+
+
+```
+
+### Global Site Schema
+
+```astro
+---
+// src/layouts/BaseLayout.astro
+import { serializeJsonForHtml } from '../lib/serialize-json-ld';
+
+const siteSchema = {
+ '@context': 'https://schema.org',
+ '@type': 'WebSite',
+ name: 'My Astro Site',
+ url: 'https://mysite.com',
+ description: 'Lightning-fast static site',
+};
+---
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Best Practices
+
+### 1. Organize Content with Collections
+
+```
+src/
+├── content/
+│ ├── blog/
+│ │ ├── post-1.md
+│ │ └── post-2.md
+│ └── docs/
+│ ├── getting-started.md
+│ └── api-reference.md
+└── pages/
+ ├── blog/
+ │ └── [slug].astro
+ └── docs/
+ └── [slug].astro
+```
+
+### 2. Use Component Islands for Performance
+
+```astro
+---
+// src/components/SearchWidget.astro
+---
+
+
+
+
+```
+
+### 3. Optimize Images
+
+```astro
+---
+import { Image } from 'astro:assets';
+import coverImage from '../assets/cover.jpg';
+---
+
+
+```
+
+### 4. Dynamic Sitemap Generation
+
+Create a dynamic endpoint for sitemaps:
+
+```typescript
+// src/pages/sitemap.xml.ts
+import { getCollection } from 'astro:content';
+
+export async function GET() {
+ const posts = await getCollection('blog');
+
+ const sitemap = `
+
+
+ https://mysite.com/
+ 1.0
+
+ ${posts.map(post => `
+
+ https://mysite.com/blog/${post.slug}/
+ ${post.data.pubDate.toISOString()}
+ 0.8
+
+ `).join('')}
+
+ `;
+
+ return new Response(sitemap, {
+ headers: { 'Content-Type': 'application/xml' },
+ });
+}
+```
+
+## Deployment
+
+### Netlify
+
+```toml
+# netlify.toml
+[build]
+ command = "npm run build"
+ publish = "dist"
+```
+
+### Vercel
+
+```json
+{
+ "buildCommand": "npm run build",
+ "outputDirectory": "dist"
+}
+```
+
+### Cloudflare Pages
+
+Works automatically - just connect your repo!
+
+## Troubleshooting
+
+### Files Not Appearing
+
+**Problem**: AEO files missing from dist.
+
+**Solution**: Ensure integration is added to `astro.config.mjs` and rebuild
+
+### Incorrect Site URL
+
+**Problem**: llms.txt shows wrong URL.
+
+**Solution**: Match `site` in config with `url` in integration:
+```javascript
+export default defineConfig({
+ site: 'https://mysite.com', // Must match
+ integrations: [
+ aeoAstroIntegration({
+ url: 'https://mysite.com', // Must match
+ }),
+ ],
+});
+```
+
+### Content Collection URLs Wrong
+
+**Problem**: Blog post URLs incorrect in sitemap.
+
+**Solution**: Use trailing slashes consistently:
+```astro
+
+```
+
+## Examples
+
+### Blog with Tags
+
+```astro
+---
+// src/pages/blog/tag/[tag].astro
+import { getCollection } from 'astro:content';
+
+export async function getStaticPaths() {
+ const posts = await getCollection('blog');
+ const tags = [...new Set(posts.flatMap(post => post.data.tags))];
+
+ return tags.map(tag => ({
+ params: { tag },
+ props: {
+ posts: posts.filter(post => post.data.tags.includes(tag)),
+ },
+ }));
+}
+
+const { tag } = Astro.params;
+const { posts } = Astro.props;
+---
+
+
+
+ Posts tagged "{tag}"
+
+
+ Posts tagged "{tag}"
+ {posts.map(post => (
+
+ {post.data.title}
+
+ ))}
+
+
+```
+
+### Documentation Site
+
+```javascript
+// astro.config.mjs
+export default defineConfig({
+ site: 'https://docs.myproject.com',
+ integrations: [
+ aeoAstroIntegration({
+ title: 'My Project Documentation',
+ description: 'Complete reference and guides',
+ url: 'https://docs.myproject.com',
+ pages: [
+ { pathname: '/', title: 'Home' },
+ { pathname: '/getting-started', title: 'Getting Started' },
+ { pathname: '/api', title: 'API Reference' },
+ ],
+ }),
+ ],
+});
+```
+
+## Further Reading
+
+- [Astro Documentation](https://docs.astro.build)
+- [Content Collections Guide](https://docs.astro.build/en/guides/content-collections/)
+- [Back to Overview](./README.md)
+
+---
+
+**Questions?** [Open an issue](https://github.com/multivmlabs/aeo.js/issues)
diff --git a/docs/nextjs.md b/docs/nextjs.md
new file mode 100755
index 0000000..1a6ea9e
--- /dev/null
+++ b/docs/nextjs.md
@@ -0,0 +1,570 @@
+# Next.js Integration Guide
+
+Complete guide for integrating aeo.js with Next.js to optimize your site for AI-powered search engines.
+
+## Prerequisites
+
+- **Next.js**: 13.0 or higher (App Router or Pages Router)
+- **Node.js**: 18.0 or higher
+- **Package Manager**: npm, yarn, or pnpm
+
+## Installation
+
+### Step 1: Install aeo.js
+
+```bash
+npm install aeo.js
+# or
+yarn add aeo.js
+# or
+pnpm add aeo.js
+```
+
+### Step 2: Update Next.js Configuration
+
+#### For App Router (Next.js 13+)
+
+```js
+// next.config.mjs
+import { withAeo } from 'aeo.js/next';
+
+export default withAeo({
+ // Your existing Next.js config keys live here
+ aeo: {
+ title: 'My Next.js Site',
+ description: 'Built with Next.js and optimized for AI discovery',
+ url: 'https://mysite.com',
+
+ },
+});
+```
+
+#### For Pages Router (Next.js 12)
+
+```js
+// next.config.js
+const { withAeo } = require('aeo.js/next');
+
+module.exports = withAeo({
+ // Your existing Next.js config
+ aeo: {
+ title: 'My Next.js Site',
+ description: 'Built with Next.js and optimized for AI discovery',
+ url: 'https://mysite.com',
+ },
+});
+```
+
+### Step 3: Add Post-Build Hook
+
+Add the post-build script to generate AEO files after build:
+
+```json
+{
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "postbuild": "node -e \"import('aeo.js/next').then(m => m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\"",
+ "start": "next start"
+ }
+}
+```
+
+### Step 4: Build and Verify
+
+```bash
+npm run build
+```
+
+Check that these files were generated in your `public` directory:
+- `public/llms.txt`
+- `public/robots.txt`
+- `public/sitemap.xml`
+
+## Configuration
+
+### Basic Configuration
+
+The shape passed under `aeo:` is the standard `AeoConfig`. The wrapping `NextAeoConfig` is just Next's own config plus an `aeo?: AeoConfig` key:
+
+```typescript
+type NextAeoConfig = {
+ aeo?: AeoConfig;
+ // ...all of your normal Next.js config keys (webpack, redirects, etc.)
+};
+```
+
+See [README.md](./README.md#configuration-options) for the full `AeoConfig` reference.
+
+### Advanced Configuration
+
+```js
+export default withAeo({
+ // Your existing Next.js config keys live here
+ aeo: {
+ title: 'My Next.js Site',
+ url: 'https://mysite.com',
+ description: 'Comprehensive resource for...',
+
+ // Toggle individual generators (all default true)
+ generators: {
+ llmsTxt: true,
+ llmsFullTxt: true,
+ robotsTxt: true,
+ sitemap: true,
+ aiIndex: true,
+ schema: true,
+ },
+
+ // Explicit page metadata. The plugin auto-discovers pages from the
+ // App Router / Pages Router, but you can override or supplement here.
+ pages: [
+ { pathname: '/', title: 'Home', description: 'Welcome to our site' },
+ { pathname: '/blog', title: 'Blog', description: 'Latest articles and tutorials' },
+ { pathname: '/docs', title: 'Documentation', description: 'Complete API reference' },
+ ],
+
+ // robots.txt directives — use these to keep crawlers out of private routes
+ robots: {
+ allow: ['/'],
+ disallow: [
+ '/api',
+ '/admin',
+ '/_next',
+ '/private',
+ ],
+ },
+
+ // JSON-LD structured data
+ schema: {
+ enabled: true,
+ organization: {
+ name: 'My Company',
+ url: 'https://mysite.com',
+ },
+ },
+ },
+});
+```
+
+## App Router Integration
+
+### Adding JSON-LD to Root Layout
+
+> When you inject JSON-LD via `dangerouslySetInnerHTML`, React does **not** escape characters that can terminate the surrounding `` (or U+2028/U+2029) would break out and execute as JavaScript. Run the payload through a serializer that escapes those characters first — this is the same `serializeJsonForHtml` aeo.js uses internally ([src/core/schema.ts](https://github.com/multivmlabs/aeo.js/blob/main/src/core/schema.ts)). aeo.js's own injected JSON-LD is already safe; only your custom additions need this.
+
+```typescript
+// app/lib/serialize-json-ld.ts
+export function serializeJsonForHtml(value: unknown): string {
+ return JSON.stringify(value)
+ .replace(//g, '\\u003E')
+ .replace(/&/g, '\\u0026')
+ .replace(/\u2028/g, '\\u2028')
+ .replace(/\u2029/g, '\\u2029');
+}
+```
+
+```typescript
+// app/layout.tsx
+import { Metadata } from 'next';
+import { serializeJsonForHtml } from './lib/serialize-json-ld';
+
+export const metadata: Metadata = {
+ title: 'My Next.js Site',
+ description: 'Optimized for AI discovery',
+};
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ return (
+
+
+
+
+ {children}
+
+ );
+}
+```
+
+### Dynamic Page Metadata
+
+```typescript
+// app/blog/[slug]/page.tsx
+import { Metadata } from 'next';
+
+// Next.js 14 and below: params is a plain object.
+// For Next.js 15+, params is a Promise — see note below.
+type Props = { params: { slug: string } };
+
+export async function generateMetadata({ params }: Props): Promise {
+ const post = await getPost(params.slug);
+
+ return {
+ title: post.title,
+ description: post.excerpt,
+ openGraph: {
+ title: post.title,
+ description: post.excerpt,
+ url: `https://mysite.com/blog/${params.slug}`,
+ type: 'article',
+ },
+ };
+}
+```
+
+> **Next.js 15+** introduced async params. Change the type to `{ params: Promise<{ slug: string }> }` and `await` it: `const { slug } = await params;`.
+
+## Pages Router Integration
+
+### Custom _app.tsx
+
+```typescript
+// pages/_app.tsx
+import type { AppProps } from 'next/app';
+import Head from 'next/head';
+
+export default function App({ Component, pageProps }: AppProps) {
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+}
+```
+
+### Page-Level SEO
+
+```typescript
+// pages/blog/[slug].tsx
+import Head from 'next/head';
+import { serializeJsonForHtml } from '@/lib/serialize-json-ld';
+
+type BlogPostProps = {
+ post: {
+ title: string;
+ excerpt: string;
+ publishedAt: string;
+ author: { name: string };
+ };
+};
+
+export default function BlogPost({ post }: BlogPostProps) {
+ return (
+ <>
+
+ {post.title} | My Blog
+
+
+
+ {/* Post content */}
+ >
+ );
+}
+```
+
+## Best Practices
+
+### 1. Dynamic Sitemap Generation
+
+For sites with many pages, generate sitemaps dynamically:
+
+```typescript
+// pages/api/sitemap.xml.ts
+import { NextApiRequest, NextApiResponse } from 'next';
+
+export default async function handler(
+ req: NextApiRequest,
+ res: NextApiResponse
+) {
+ const posts = await getAllPosts();
+
+ const sitemap = `
+
+ ${posts.map(post => `
+
+ https://mysite.com/blog/${post.slug}
+ ${new Date(post.updatedAt).toISOString()}
+ 0.8
+
+ `).join('')}
+
+ `;
+
+ res.setHeader('Content-Type', 'text/xml');
+ res.write(sitemap);
+ res.end();
+}
+```
+
+### 2. Structured Data for Blog Posts
+
+```typescript
+const blogPostSchema = {
+ '@context': 'https://schema.org',
+ '@type': 'BlogPosting',
+ headline: post.title,
+ description: post.excerpt,
+ image: post.coverImage,
+ datePublished: post.publishedAt,
+ dateModified: post.updatedAt,
+ author: {
+ '@type': 'Person',
+ name: post.author.name,
+ url: post.author.url,
+ },
+ publisher: {
+ '@type': 'Organization',
+ name: 'My Site',
+ logo: {
+ '@type': 'ImageObject',
+ url: 'https://mysite.com/logo.png',
+ },
+ },
+};
+```
+
+### 3. Optimize Static Assets
+
+```typescript
+// next.config.mjs
+export default withAeo({
+ images: {
+ domains: ['cdn.mysite.com'],
+ formats: ['image/avif', 'image/webp'],
+ },
+ aeo: {
+ // ... config
+ },
+});
+```
+
+### 4. Environment-Specific Configuration
+
+```typescript
+// next.config.mjs
+const isProd = process.env.NODE_ENV === 'production';
+
+export default withAeo({
+ // Your existing Next.js config keys live here
+ aeo: {
+ title: 'My Site',
+ url: isProd ? 'https://mysite.com' : 'http://localhost:3000',
+ generators: { sitemap: isProd }, // Only in production
+ },
+});
+```
+
+## Deployment
+
+### Vercel
+
+aeo.js works automatically with Vercel deployments:
+
+1. Push your code to GitHub
+2. Connect to Vercel
+3. Deploy
+4. Files are generated during build
+
+Verify at:
+- `https://yoursite.vercel.app/llms.txt`
+- `https://yoursite.vercel.app/sitemap.xml`
+
+### Self-Hosted
+
+Ensure the post-build hook runs:
+
+```bash
+npm run build
+npm run start
+```
+
+### Docker
+
+```dockerfile
+FROM node:18-alpine
+
+WORKDIR /app
+COPY package*.json ./
+RUN npm ci
+COPY . .
+RUN npm run build
+
+EXPOSE 3000
+CMD ["npm", "start"]
+```
+
+## Troubleshooting
+
+### Files Not Generated
+
+**Problem**: llms.txt or sitemap.xml not appearing in public directory.
+
+**Solutions**:
+1. Check that `postbuild` script runs: `npm run build` should show aeo.js output
+2. Verify Next.js version is 13+
+3. Check build output directory permissions
+4. Ensure `public` directory exists
+
+### Build Errors
+
+**Problem**: `Cannot find module 'aeo.js/next'`
+
+**Solution**:
+```bash
+rm -rf node_modules package-lock.json
+npm install
+```
+
+### Incorrect URLs in Sitemap
+
+**Problem**: Sitemap contains localhost URLs in production.
+
+**Solution**: Set `url` in config to production URL:
+```js
+url: 'https://mysite.com', // Not localhost
+```
+
+### Missing Pages in Sitemap
+
+**Problem**: Dynamic routes not appearing in sitemap.
+
+**Solution**: Use `pages` to explicitly list dynamic routes:
+```js
+pages: [
+ { pathname: '/blog/post-1', title: 'Post 1' },
+ { pathname: '/blog/post-2', title: 'Post 2' },
+],
+```
+
+## Examples
+
+### Blog with MDX
+
+```typescript
+// next.config.mjs
+import { withAeo } from 'aeo.js/next';
+import mdx from '@next/mdx';
+
+const withMDX = mdx();
+
+export default withAeo(withMDX({
+ pageExtensions: ['ts', 'tsx', 'md', 'mdx'],
+ aeo: {
+ title: 'My Blog',
+ description: 'Technical articles and tutorials',
+ url: 'https://myblog.com',
+ },
+}));
+```
+
+### E-commerce Site
+
+```typescript
+export default withAeo({
+ // Your existing Next.js config keys live here
+ aeo: {
+ title: 'My Store',
+ description: 'Quality products, fast shipping',
+ url: 'https://mystore.com',
+ robots: {
+ allow: ['/'],
+ disallow: ['/checkout', '/account', '/api'],
+ },
+ pages: [
+ { pathname: '/', title: 'Home' },
+ { pathname: '/products', title: 'Products' },
+ { pathname: '/about', title: 'About' },
+ ],
+ },
+});
+```
+
+### Documentation Site
+
+```typescript
+export default withAeo({
+ // Your existing Next.js config keys live here
+ aeo: {
+ title: 'API Documentation',
+ description: 'Complete API reference and guides',
+ url: 'https://docs.myapi.com',
+
+ pages: [
+ { pathname: '/api-reference', title: 'API Reference' },
+ { pathname: '/guides', title: 'Guides' },
+ { pathname: '/examples', title: 'Examples' },
+ ],
+ },
+});
+```
+
+## Testing
+
+### Verify llms.txt
+
+```bash
+curl http://localhost:3000/llms.txt
+```
+
+Expected output:
+```
+# My Next.js Site
+
+> Built with Next.js and optimized for AI discovery
+
+## Site Information
+- URL: https://mysite.com
+...
+```
+
+### Test with AI
+
+Ask ChatGPT or Claude:
+> "What can you tell me about [your site URL]?"
+
+The AI should be able to reference your llms.txt content.
+
+## Further Reading
+
+- [Next.js Documentation](https://nextjs.org/docs)
+- [Structured Data Guide](https://developers.google.com/search/docs/advanced/structured-data/intro-structured-data)
+- [Back to Overview](./README.md)
+
+---
+
+**Questions or issues?** [Open an issue on GitHub](https://github.com/multivmlabs/aeo.js/issues)
diff --git a/docs/nuxt.md b/docs/nuxt.md
new file mode 100755
index 0000000..07b934b
--- /dev/null
+++ b/docs/nuxt.md
@@ -0,0 +1,491 @@
+# Nuxt Integration Guide
+
+Complete guide for integrating aeo.js with Nuxt to optimize your site for AI-powered search engines.
+
+## Prerequisites
+
+- **Nuxt**: 3.0 or higher
+- **Node.js**: 18.0 or higher
+- **Package Manager**: npm, yarn, or pnpm
+
+## Installation
+
+### Step 1: Install aeo.js
+
+```bash
+npm install aeo.js
+# or
+yarn add aeo.js
+# or
+pnpm add aeo.js
+```
+
+### Step 2: Add Module to Nuxt Config
+
+```typescript
+// nuxt.config.ts
+export default defineNuxtConfig({
+ modules: ['aeo.js/nuxt'],
+
+ aeo: {
+ title: 'My Nuxt Site',
+ description: 'Built with Nuxt and optimized for AI discovery',
+ url: 'https://mysite.com',
+
+ },
+});
+```
+
+### Step 3: Build and Verify
+
+```bash
+npm run build
+```
+
+Check generated files in `.output/public`:
+- `.output/public/llms.txt`
+- `.output/public/robots.txt`
+- `.output/public/sitemap.xml`
+
+## Configuration
+
+### Basic Configuration
+
+The `aeo` block accepts the standard `AeoConfig`. See [README.md](./README.md#configuration-options) for the full reference.
+
+### Advanced Configuration
+
+```typescript
+export default defineNuxtConfig({
+ modules: ['aeo.js/nuxt'],
+
+ aeo: {
+ title: 'My Nuxt Site',
+ url: 'https://mysite.com',
+ description: 'Server-rendered Vue application',
+
+ // Toggle individual generators (all default true)
+ generators: {
+ llmsTxt: true,
+ llmsFullTxt: true,
+ robotsTxt: true,
+ sitemap: true,
+ aiIndex: true,
+ schema: true,
+ },
+
+ // Optional explicit page metadata (the module auto-discovers from pages/)
+ pages: [
+ { pathname: '/', title: 'Home', description: 'Welcome page' },
+ { pathname: '/blog', title: 'Blog', description: 'Latest articles' },
+ ],
+
+ // robots.txt — block crawlers from private routes
+ robots: {
+ allow: ['/'],
+ disallow: ['/admin', '/api', '/_nuxt'],
+ },
+
+ schema: {
+ enabled: true,
+ organization: {
+ name: 'My Nuxt Site',
+ url: 'https://mysite.com',
+ },
+ },
+ },
+});
+```
+
+## Page Meta & SEO
+
+> `useHead` writes `children` as the script body verbatim — it does **not** escape characters that can terminate the surrounding `` (or U+2028/U+2029) would break out and execute as JavaScript. Run the payload through a serializer that escapes those characters first — the helper below is the same `serializeJsonForHtml` aeo.js uses internally ([src/core/schema.ts](https://github.com/multivmlabs/aeo.js/blob/main/src/core/schema.ts)). aeo.js's own injected JSON-LD is already safe; only your custom additions need this.
+
+```ts
+// utils/serialize-json-ld.ts
+export function serializeJsonForHtml(value: unknown): string {
+ return JSON.stringify(value)
+ .replace(//g, '\\u003E')
+ .replace(/&/g, '\\u0026')
+ .replace(/\u2028/g, '\\u2028')
+ .replace(/\u2029/g, '\\u2029');
+}
+```
+
+### Using useHead Composable
+
+```vue
+
+
+
+
+
My Page
+
+
+```
+
+### Dynamic Meta from API
+
+```vue
+
+```
+
+## Content Module Integration
+
+### Setup Nuxt Content
+
+```bash
+npm install @nuxt/content
+```
+
+```typescript
+// nuxt.config.ts
+export default defineNuxtConfig({
+ modules: ['@nuxt/content', 'aeo.js/nuxt'],
+
+ content: {
+ highlight: {
+ theme: 'github-dark',
+ },
+ },
+
+ aeo: {
+ title: 'My Blog',
+ url: 'https://myblog.com',
+ },
+});
+```
+
+### Content-Driven Pages
+
+```vue
+
+
+
+
+ {{ article.title }}
+
+
+
+```
+
+## Best Practices
+
+### 1. App-Level Configuration
+
+```vue
+
+
+
+
+
+
+```
+
+### 2. Server Routes for Dynamic Sitemaps
+
+```typescript
+// server/routes/sitemap.xml.ts
+type Post = { slug: string; updatedAt: string | Date };
+
+export default defineEventHandler(async (event) => {
+ // $fetch defaults to `T = unknown` — pass the response type explicitly
+ // so `.map()` is type-safe under "strict": true.
+ const posts = await $fetch('/api/posts');
+
+ const sitemap = `
+
+
+ https://mysite.com/
+ 1.0
+
+ ${posts.map(post => `
+
+ https://mysite.com/blog/${post.slug}
+ ${new Date(post.updatedAt).toISOString()}
+ 0.8
+
+ `).join('')}
+
+ `;
+
+ setHeader(event, 'Content-Type', 'application/xml');
+ return sitemap;
+});
+```
+
+### 3. Environment-Specific Config
+
+```typescript
+// nuxt.config.ts
+const isProd = process.env.NODE_ENV === 'production';
+
+export default defineNuxtConfig({
+ modules: ['aeo.js/nuxt'],
+
+ aeo: {
+ title: 'My Site',
+ url: isProd ? 'https://mysite.com' : 'http://localhost:3000',
+ generators: { sitemap: isProd },
+ },
+});
+```
+
+### 4. Composables for Structured Data
+
+```typescript
+// composables/useStructuredData.ts
+import { serializeJsonForHtml } from '~/utils/serialize-json-ld';
+
+export const useStructuredData = (type: string, data: Record) => {
+ useHead({
+ script: [
+ {
+ type: 'application/ld+json',
+ children: serializeJsonForHtml({
+ '@context': 'https://schema.org',
+ '@type': type,
+ ...data,
+ }),
+ },
+ ],
+ });
+};
+```
+
+Usage:
+```vue
+
+```
+
+## Deployment
+
+### Vercel
+
+```json
+// vercel.json
+{
+ "buildCommand": "npm run build",
+ "outputDirectory": ".output/public"
+}
+```
+
+### Netlify
+
+```toml
+# netlify.toml
+[build]
+ command = "npm run build"
+ publish = ".output/public"
+```
+
+### Node Server
+
+```bash
+npm run build
+node .output/server/index.mjs
+```
+
+## Troubleshooting
+
+### Module Not Found
+
+**Problem**: `Cannot find module 'aeo.js/nuxt'`
+
+**Solution**:
+```bash
+rm -rf node_modules .nuxt
+npm install
+```
+
+### Files in Wrong Directory
+
+**Problem**: AEO files in wrong output location.
+
+**Solution**: Check Nuxt version - v3 uses `.output/public`
+
+### SSR vs Static Generation
+
+**Problem**: Different behavior between `nuxt build` and `nuxt generate`.
+
+**Solution**: Use `nuxt generate` for static sites:
+```bash
+npx nuxi generate
+```
+
+## Examples
+
+### Blog with Categories
+
+```vue
+
+
+
+
+
+
{{ category }} Posts
+
+
+ {{ post.title }}
+
+
+
+
+```
+
+### E-commerce Product Pages
+
+```vue
+
+```
+
+## Further Reading
+
+- [Nuxt Documentation](https://nuxt.com/docs)
+- [Nuxt Content](https://content.nuxt.com)
+- [Nuxt SEO](https://nuxtseo.com)
+- [Back to Overview](./README.md)
+
+---
+
+**Need help?** [Open an issue](https://github.com/multivmlabs/aeo.js/issues)
diff --git a/docs/vite.md b/docs/vite.md
new file mode 100755
index 0000000..248276d
--- /dev/null
+++ b/docs/vite.md
@@ -0,0 +1,543 @@
+# Vite Integration Guide
+
+Complete guide for integrating aeo.js with Vite to optimize your site for AI-powered search engines.
+
+## Prerequisites
+
+- **Vite**: 4.0 or higher
+- **Node.js**: 18.0 or higher
+- **Framework**: Works with React, Vue, Svelte, Solid, or vanilla JS
+
+## Installation
+
+### Step 1: Install aeo.js
+
+```bash
+npm install aeo.js
+# or
+yarn add aeo.js
+# or
+pnpm add aeo.js
+```
+
+### Step 2: Add Plugin to Vite Config
+
+```typescript
+// vite.config.ts
+import { defineConfig } from 'vite';
+import { aeoVitePlugin } from 'aeo.js/vite';
+
+export default defineConfig({
+ plugins: [
+ aeoVitePlugin({
+ title: 'My Vite Site',
+ description: 'Built with Vite and optimized for AI discovery',
+ url: 'https://mysite.com',
+
+ }),
+ ],
+});
+```
+
+### Step 3: Build and Verify
+
+```bash
+npm run build
+```
+
+Check generated files in `dist`:
+- `dist/llms.txt`
+- `dist/robots.txt`
+- `dist/sitemap.xml`
+
+## Framework-Specific Setup
+
+### React + Vite
+
+```typescript
+// vite.config.ts
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+import { aeoVitePlugin } from 'aeo.js/vite';
+
+export default defineConfig({
+ plugins: [
+ react(),
+ aeoVitePlugin({
+ title: 'My React App',
+ url: 'https://myapp.com',
+ description: 'React application optimized for AI',
+ }),
+ ],
+});
+```
+
+### Vue + Vite
+
+```typescript
+// vite.config.ts
+import { defineConfig } from 'vite';
+import vue from '@vitejs/plugin-vue';
+import { aeoVitePlugin } from 'aeo.js/vite';
+
+export default defineConfig({
+ plugins: [
+ vue(),
+ aeoVitePlugin({
+ title: 'My Vue App',
+ url: 'https://myapp.com',
+ description: 'Vue application with AEO',
+ }),
+ ],
+});
+```
+
+### Svelte + Vite
+
+```typescript
+// vite.config.ts
+import { defineConfig } from 'vite';
+import { svelte } from '@sveltejs/vite-plugin-svelte';
+import { aeoVitePlugin } from 'aeo.js/vite';
+
+export default defineConfig({
+ plugins: [
+ svelte(),
+ aeoVitePlugin({
+ title: 'My Svelte App',
+ url: 'https://myapp.com',
+ }),
+ ],
+});
+```
+
+## Configuration
+
+### Basic Configuration
+
+`aeoVitePlugin` accepts the standard `AeoConfig`. See [README.md](./README.md#configuration-options) for the full reference.
+
+### Advanced Configuration
+
+```typescript
+aeoVitePlugin({
+ title: 'My Vite Site',
+ url: 'https://mysite.com',
+ description: 'Lightning-fast web application',
+
+ // Toggle individual generators (all default true)
+ generators: {
+ llmsTxt: true,
+ llmsFullTxt: true,
+ robotsTxt: true,
+ sitemap: true,
+ aiIndex: true,
+ schema: true,
+ },
+
+ // Optional explicit page metadata (the plugin auto-discovers from your routes)
+ pages: [
+ { pathname: '/', title: 'Home', description: 'Welcome to our app' },
+ { pathname: '/features', title: 'Features', description: 'App features' },
+ ],
+
+ // robots.txt — block crawlers from private routes
+ robots: {
+ allow: ['/'],
+ disallow: ['/admin'],
+ },
+
+ schema: {
+ enabled: true,
+ organization: {
+ name: 'My Vite Site',
+ url: 'https://mysite.com',
+ },
+ },
+})
+```
+
+## Adding Metadata
+
+> All three patterns below render JSON-LD as the body of a `` (or U+2028 / U+2029, anywhere in the payload including user-controlled titles) breaks out of the script block and executes as arbitrary JavaScript. Run the payload through a serializer that escapes those characters first — this is the same `serializeJsonForHtml` aeo.js uses internally ([src/core/schema.ts](https://github.com/multivmlabs/aeo.js/blob/main/src/core/schema.ts)). aeo.js's own injected JSON-LD is already safe; only your custom additions need this.
+
+```typescript
+// src/lib/serialize-json-ld.ts
+export function serializeJsonForHtml(value: unknown): string {
+ return JSON.stringify(value)
+ .replace(//g, '\\u003E')
+ .replace(/&/g, '\\u0026')
+ .replace(/\u2028/g, '\\u2028')
+ .replace(/\u2029/g, '\\u2029');
+}
+```
+
+### React with Helmet
+
+```bash
+npm install react-helmet-async
+```
+
+```typescript
+// App.tsx
+import { Helmet } from 'react-helmet-async';
+import { serializeJsonForHtml } from './lib/serialize-json-ld';
+
+export default function App() {
+ const schema = serializeJsonForHtml({
+ '@context': 'https://schema.org',
+ '@type': 'WebApplication',
+ name: 'My App',
+ url: 'https://myapp.com',
+ });
+
+ return (
+ <>
+
+ My App
+
+
+
+ {/* App content */}
+ >
+ );
+}
+```
+
+### Vue with useHead
+
+```bash
+npm install @unhead/vue
+```
+
+```vue
+
+
+
+
+
My App
+
+
+```
+
+### Svelte with svelte:head
+
+```svelte
+
+
+
+ My Svelte App
+
+ {@html ``}
+
+
+
+ My App
+
+```
+
+## Best Practices
+
+### 1. Environment Variables
+
+```typescript
+// vite.config.ts
+export default defineConfig(({ mode }) => ({
+ plugins: [
+ aeoVitePlugin({
+ title: 'My Site',
+ url: mode === 'production'
+ ? 'https://mysite.com'
+ : 'http://localhost:5173',
+ generators: { sitemap: mode === 'production' },
+ }),
+ ],
+}));
+```
+
+### 2. Multi-Page Applications
+
+```typescript
+// vite.config.ts
+import { defineConfig } from 'vite';
+import { resolve, dirname } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { aeoVitePlugin } from 'aeo.js/vite';
+
+// ESM doesn't ship __dirname — derive it from import.meta.url
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+export default defineConfig({
+ build: {
+ rollupOptions: {
+ input: {
+ main: resolve(__dirname, 'index.html'),
+ about: resolve(__dirname, 'about/index.html'),
+ blog: resolve(__dirname, 'blog/index.html'),
+ },
+ },
+ },
+ plugins: [
+ aeoVitePlugin({
+ title: 'My Site',
+ url: 'https://mysite.com',
+ pages: [
+ { pathname: '/', title: 'Home' },
+ { pathname: '/about', title: 'About' },
+ { pathname: '/blog', title: 'Blog' },
+ ],
+ }),
+ ],
+});
+```
+
+### 3. Asset Optimization
+
+```typescript
+export default defineConfig({
+ build: {
+ cssCodeSplit: true,
+ sourcemap: false,
+ minify: 'terser',
+ terserOptions: {
+ compress: {
+ drop_console: true,
+ },
+ },
+ },
+ plugins: [
+ aeoVitePlugin({ /* config */ }),
+ ],
+});
+```
+
+### 4. Custom Build Output
+
+```typescript
+export default defineConfig({
+ build: {
+ outDir: 'build', // Custom output directory
+ },
+ plugins: [
+ aeoVitePlugin({
+ title: 'My Site',
+ url: 'https://mysite.com',
+ // Files will be generated in 'build' directory
+ }),
+ ],
+});
+```
+
+## Deployment
+
+### Static Hosting (Netlify, Vercel)
+
+1. Build your app:
+```bash
+npm run build
+```
+
+2. Deploy `dist` folder
+
+3. Verify files at:
+- `https://yoursite.com/llms.txt`
+- `https://yoursite.com/sitemap.xml`
+
+### GitHub Pages
+
+```yaml
+# .github/workflows/deploy.yml
+name: Deploy
+
+on:
+ push:
+ branches: [main]
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: '18'
+ - run: npm ci
+ - run: npm run build
+ - uses: peaceiris/actions-gh-pages@v3
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: ./dist
+```
+
+### Docker
+
+```dockerfile
+# Build stage
+FROM node:18-alpine AS builder
+WORKDIR /app
+COPY package*.json ./
+RUN npm ci
+COPY . .
+RUN npm run build
+
+# Production stage
+FROM nginx:alpine
+COPY --from=builder /app/dist /usr/share/nginx/html
+EXPOSE 80
+CMD ["nginx", "-g", "daemon off;"]
+```
+
+## Troubleshooting
+
+### Plugin Not Running
+
+**Problem**: AEO files not generated.
+
+**Solution**: Ensure plugin is in `plugins` array:
+```typescript
+export default defineConfig({
+ plugins: [
+ aeoVitePlugin({ /* config */ }), // Must be here
+ ],
+});
+```
+
+### Wrong Output Directory
+
+**Problem**: Files generated in wrong location.
+
+**Solution**: Match build.outDir:
+```typescript
+export default defineConfig({
+ build: {
+ outDir: 'dist', // Default
+ },
+ plugins: [
+ aeoVitePlugin({ /* config */ }),
+ ],
+});
+```
+
+### HMR Issues
+
+**Problem**: Hot module reload not working with AEO.
+
+**Solution**: AEO only runs on build, not during dev. This is expected.
+
+### Path Resolution in SPAs
+
+**Problem**: Routes not found in sitemap (SPA mode).
+
+**Solution**: List routes explicitly:
+```typescript
+aeoVitePlugin({
+ pages: [
+ { pathname: '/', title: 'Home' },
+ { pathname: '/about', title: 'About' },
+ { pathname: '/contact', title: 'Contact' },
+ ],
+})
+```
+
+## Examples
+
+### React SPA with Routing
+
+```typescript
+// vite.config.ts
+export default defineConfig({
+ plugins: [
+ react(),
+ aeoVitePlugin({
+ title: 'My React SPA',
+ url: 'https://myapp.com',
+ pages: [
+ { pathname: '/', title: 'Home' },
+ { pathname: '/products', title: 'Products' },
+ { pathname: '/about', title: 'About' },
+ ],
+ }),
+ ],
+});
+```
+
+### Vue Documentation Site
+
+```typescript
+export default defineConfig({
+ plugins: [
+ vue(),
+ aeoVitePlugin({
+ title: 'Vue Docs',
+ description: 'Complete Vue.js documentation',
+ url: 'https://docs.vue-app.com',
+ pages: [
+ { pathname: '/', title: 'Home' },
+ { pathname: '/guide', title: 'Guide' },
+ { pathname: '/api', title: 'API Reference' },
+ ],
+ }),
+ ],
+});
+```
+
+### Svelte Portfolio
+
+```typescript
+export default defineConfig({
+ plugins: [
+ svelte(),
+ aeoVitePlugin({
+ title: 'John Doe - Portfolio',
+ description: 'Web developer portfolio',
+ url: 'https://johndoe.com',
+
+ pages: [
+ { pathname: '/', title: 'Home' },
+ { pathname: '/projects', title: 'Projects' },
+ { pathname: '/blog', title: 'Blog' },
+ { pathname: '/contact', title: 'Contact' },
+ ],
+ }),
+ ],
+});
+```
+
+## Further Reading
+
+- [Vite Documentation](https://vitejs.dev)
+- [Vite Plugin API](https://vitejs.dev/guide/api-plugin.html)
+- [Back to Overview](./README.md)
+
+---
+
+**Need help?** [Open an issue](https://github.com/multivmlabs/aeo.js/issues)
diff --git a/docs/webpack.md b/docs/webpack.md
new file mode 100644
index 0000000..d693d88
--- /dev/null
+++ b/docs/webpack.md
@@ -0,0 +1,217 @@
+# Webpack Integration Guide
+
+Make your webpack-built site discoverable by AI search engines like ChatGPT, Claude, Perplexity, and SearchGPT.
+
+## Prerequisites
+
+- Node.js 18+
+- A project using webpack 5+
+- TypeScript is optional but recommended
+
+## Installation
+
+```bash
+npm install aeo.js
+# or
+yarn add aeo.js
+# or
+pnpm add aeo.js
+```
+
+## Quick Start
+
+aeo.js ships a webpack plugin that hooks into the `afterEmit` lifecycle, scans the emitted HTML assets in your output directory, and generates AEO files alongside them.
+
+### Step 1: Register the plugin
+
+```js
+// webpack.config.js
+const { AeoWebpackPlugin } = require('aeo.js/webpack');
+
+module.exports = {
+ // ...your existing webpack config
+ plugins: [
+ new AeoWebpackPlugin({
+ title: 'My Site',
+ description: 'Optimized for AI discovery',
+ url: 'https://mysite.com',
+ }),
+ ],
+};
+```
+
+### Step 2: Build and verify
+
+```bash
+npm run build
+```
+
+You should now have these files in your webpack `output.path` directory:
+
+- `robots.txt` — AI crawler directives
+- `llms.txt` — short summary for LLMs
+- `llms-full.txt` — full content dump
+- `sitemap.xml` — sitemap
+- `ai-index.json` — chunked content for embedding
+- `docs.json` — site manifest
+- `schema.json` — JSON-LD structured data (when `schema.enabled`)
+- Per-page `.md` files (when `generators.rawMarkdown` is enabled)
+
+## Configuration
+
+### Basic Configuration
+
+The plugin accepts the standard `AeoConfig`. The minimum useful shape:
+
+```typescript
+type AeoConfig = {
+ title?: string; // Strongly recommended (defaults to "My Site")
+ url?: string; // Strongly recommended (your production URL)
+ description?: string; // Recommended
+ outDir?: string; // Where to write AEO files (defaults to webpack output.path)
+ contentDir?: string; // Optional handwritten-markdown source
+};
+```
+
+> Although `title` and `url` are optional in the type, omitting `url` causes `sitemap.xml`, `llms.txt`, and JSON-LD to fall back to `https://example.com`. Always set it for production builds. See [README.md](./README.md#configuration-options) for the full reference.
+
+### Advanced Configuration
+
+```js
+const { AeoWebpackPlugin } = require('aeo.js/webpack');
+
+module.exports = {
+ plugins: [
+ new AeoWebpackPlugin({
+ title: 'My Site',
+ url: 'https://mysite.com',
+ description: 'Lightning-fast site built with webpack',
+
+ generators: {
+ robotsTxt: true,
+ llmsTxt: true,
+ llmsFullTxt: true,
+ sitemap: true,
+ aiIndex: true,
+ schema: true,
+ rawMarkdown: true,
+ },
+
+ robots: {
+ allow: ['/'],
+ disallow: ['/admin'],
+ },
+
+ schema: {
+ enabled: true,
+ organization: {
+ name: 'My Company',
+ url: 'https://mysite.com',
+ },
+ },
+
+ aiIndex: {
+ maxChunkLength: 2000,
+ maxKeywords: 10,
+ },
+ }),
+ ],
+};
+```
+
+### Factory Form
+
+If you prefer a function-style API:
+
+```js
+const { createAeoWebpackPlugin } = require('aeo.js/webpack');
+
+module.exports = {
+ plugins: [
+ createAeoWebpackPlugin({
+ title: 'My Site',
+ url: 'https://mysite.com',
+ }),
+ ],
+};
+```
+
+## How It Works
+
+1. webpack runs your build and emits HTML assets to `output.path`.
+2. The `afterEmit` hook fires; the plugin walks `compilation.assets` for every `.html` file (skipping `404.html` / `500.html`).
+3. For each page it extracts the ``, meta description, and text content.
+4. It then writes the AEO files to the same output directory.
+
+Because the plugin reads the rendered HTML, it works with any HTML output webpack can produce — including `html-webpack-plugin`, `mini-html-webpack-plugin`, multi-page apps, and prerendered SPAs.
+
+## Common Setups
+
+### `html-webpack-plugin`
+
+```js
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const { AeoWebpackPlugin } = require('aeo.js/webpack');
+
+module.exports = {
+ plugins: [
+ new HtmlWebpackPlugin({ template: './src/index.html', filename: 'index.html' }),
+ new HtmlWebpackPlugin({ template: './src/about.html', filename: 'about/index.html' }),
+ new AeoWebpackPlugin({
+ title: 'My Site',
+ url: 'https://mysite.com',
+ }),
+ ],
+};
+```
+
+### Multi-page SPA
+
+For SPAs with multiple entry points or prerendered routes, you can supplement the auto-discovered pages with `pages` to give better titles and descriptions:
+
+```js
+new AeoWebpackPlugin({
+ title: 'My SPA',
+ url: 'https://mysite.com',
+ pages: [
+ { pathname: '/', title: 'Home', description: 'Welcome' },
+ { pathname: '/pricing', title: 'Pricing', description: 'Plans and tiers' },
+ ],
+});
+```
+
+## Best Practices
+
+- **Set `url` to your production hostname.** It seeds `sitemap.xml`, absolute URLs in `llms.txt`, and JSON-LD.
+- **Run AEO generation only in production builds.** Gate the plugin behind your `NODE_ENV`:
+
+ ```js
+ const isProd = process.env.NODE_ENV === 'production';
+
+ module.exports = {
+ plugins: [
+ ...(isProd ? [new AeoWebpackPlugin({ title: 'My Site', url: 'https://mysite.com' })] : []),
+ ],
+ };
+ ```
+- **Verify after deploy.** Visit `https://mysite.com/llms.txt`, `/robots.txt`, and `/sitemap.xml` to confirm the AEO files actually shipped.
+
+## Troubleshooting
+
+### No AEO files in the output directory
+The plugin only acts on HTML assets. If your webpack config produces no `.html` files (pure asset pipeline), use the CLI form instead:
+```bash
+npx aeo.js generate --url https://mysite.com --title "My Site" --out dist
+```
+
+### `llms.txt` is empty
+The plugin scans `compilation.assets` after `afterEmit`. If you use a custom emitter or post-processing that runs later, the plugin may run before your HTML is emitted. Move `AeoWebpackPlugin` to be the **last** plugin in your `plugins` array.
+
+### Sitemap is missing pages
+Multi-page SPAs that render at runtime are invisible at build time. Add the routes via the `pages` option (shown above) so the sitemap picks them up.
+
+## Further Reading
+
+- [aeo.js Reference Configuration](https://aeojs.org/reference/configuration/)
+- [Generated Files](https://aeojs.org/features/generated-files/)
+- [GEO Audit & Citability](https://aeojs.org/features/audit/)