Skip to content

Remix

  1. Install the package:

    Terminal window
    npm install aeo.js
  2. Add a post-build step to your package.json:

    {
    "scripts": {
    "postbuild": "node -e \"import('aeo.js/remix').then(m => m.postBuild({ title: 'My Site', url: 'https://mysite.com' }))\""
    }
    }
  3. Build your app:

    Terminal window
    npm run build

The Remix plugin:

  • Detects the static assets directory: build/client for Vite-based Remix / React Router 7, public/ for the classic compiler
  • Scans app/routes flat-file routes (_index.tsx, about.tsx, blog._index.tsx, folder routes with route.tsx) — pathless layouts (_marketing.) and optional segments (($lang).) are resolved, dynamic segments ($slug) are skipped
  • Scans prerendered HTML (React Router's prerender option) for titles, descriptions, and full text content
  • Generates all AEO files (robots.txt, llms.txt, sitemap.xml, ai-index.json, …) into the static assets directory so they're served from the site root

Remix renders HTML on the server, so add the widget script to your root route once:

app/root.tsx
import { getWidgetScript } from 'aeo.js/remix';
const widgetScript = getWidgetScript({
title: 'My Site',
url: 'https://mysite.com',
});
// In your Layout component, before </body>:
<div dangerouslySetInnerHTML={{ __html: widgetScript }} />

Generate AEO files from source routes without a build — files land in public/:

import { generate } from 'aeo.js/remix';
await generate({ title: 'My Site', url: 'https://mysite.com' });

Pass any AeoConfig options to postBuild or generate:

import { postBuild } from 'aeo.js/remix';
await postBuild({
title: 'My Site',
url: 'https://mysite.com',
description: 'A site optimized for AI discovery',
schema: { organization: { name: 'My Company' } },
});