Labels.io

SEO & LLMO

Rank on Google, get cited by AI assistants — wired in, nothing to build.

Technical SEO and the AI-assistant layer (LLMO) are already wired into the kit. This page covers what ships, and the three things you should set before you go live.

What ships (already done)

On every page, handled centrally in app/lib/seo.ts and the root layout:

  • Meta title and description per route
  • Open Graph and Twitter cards (rich link previews)
  • JSON-LD structured data (SoftwareApplication / organization schema)
  • Server-side rendering — every page is real HTML, not a JS shell, so crawlers and LLMs read it directly

Three real static files in public/, generated from the public route manifest (app/lib/routes-manifest.ts) + app/lib/brand.ts by scripts/generate-seo.mjs. They're rewritten automatically every time you run pnpm dev or pnpm build (the dev / build scripts call the generator first), so they never drift when you add or remove pages:

  • public/robots.txt → served at /robots.txt — crawl rules + a pointer to the sitemap
  • public/sitemap.xml → served at /sitemap.xml — every crawlable page
  • public/llms.txt → served at /llms.txt — the LLMO endpoint (llmstxt.org): a plain-text map of your site so ChatGPT, Gemini, and Claude can find and cite your product

Real files, but still auto-synced

These are actual files you can open in public/ — so they also work on pure-static hosting. You never hand-edit them: all three read the same publicRoutes list, and pnpm dev / pnpm build (or pnpm gen:seo) regenerate them. Add a page to the manifest once and all three update.

What you should do (3 things)

  1. Set your domain. Open app/lib/routes-manifest.ts and change SITE_URL from https://yourdomain.com to your real domain. Canonical URLs, the sitemap, robots, and llms.txt all use it.
  2. Add a social image. Drop a public/og.png (1200×630) — it's the image shown when your links are shared on social and in chat. The kit references /og.png already; it just needs the file.
  3. Write your description. Edit BRAND_DESCRIPTION (and BRAND) in app/lib/brand.ts. It drives the default meta description and the llms.txt summary.

When you add a new page

  1. Add its path to publicRoutes in app/lib/routes-manifest.ts. The next pnpm dev / pnpm build regenerates public/{sitemap.xml,robots.txt,llms.txt} so they pick it up automatically (or run pnpm gen:seo to refresh immediately).

  2. In the route's head(), use the seo() helper so it gets a proper title, description, and Open Graph / Twitter tags:

    import { seo } from '~/lib/seo'
    
    export const Route = createFileRoute('/{-$locale}/features')({
      head: () => ({
        meta: seo({
          title: 'Features',
          description: 'What the product does, in one sentence.',
          path: '/features',
        }),
      }),
      component: Features,
    })

Or just say "add SEO" to your AI agent — the add-seo skill wires the manifest entry and the seo() call for you.

On this page