prestruct docs

Prestruct handles technical SEO at build time. This guide covers best practices.

How Prestruct Works

Prestruct prerenders each route to static HTML with:

Configuration

Define routes in ssr.config.js:

export default {
  siteUrl: 'https://example.com',
  siteName: 'Example',
  ogImage: 'https://example.com/og-image.png',
  routes: [
    {
      path: '/',
      priority: '1.0',
      changefreq: 'weekly',
      meta: {
        title: 'Home | Example',
        description: 'Your homepage description (150-160 chars)',
      }
    },
    {
      path: '/about/',
      priority: '0.8',
      changefreq: 'monthly',
      meta: {
        title: 'About Us | Example',
        description: 'Learn more about our company...',
      }
    }
  ]
}

Meta Best Practices

Title Tags

Descriptions

Canonical URLs

Canonical is siteUrl + the route path, minus the trailing slash on /:

// Route path written with a trailing slash
{ path: '/about/' }
// Generates: <link rel="canonical" href="https://example.com/about/" />

// Root is the bare site origin (no trailing slash)
{ path: '/' }
// Generates: <link rel="canonical" href="https://example.com" />

usePageMeta computes the same value client-side on SPA navigation, so the canonical never flips between SSR and client.

Structured Data (JSON-LD)

Add schema.org data in ssr.config.js:

export default {
  // ...other config
  buildJsonLd() {
    return [
      {
        '@context': 'https://schema.org',
        '@type': 'Organization',
        name: 'Example Inc',
        url: 'https://example.com',
        logo: 'https://example.com/logo.png',
        contactPoint: {
          '@type': 'ContactPoint',
          telephone: '+1-555-1234',
          contactType: 'customer service'
        }
      }
    ]
  }
}

The returned object(s) are injected as <script type="application/ld+json"> into every page. buildJsonLd` is called with no arguments and cannot vary by route – see Structured Data for the full set of types and the per-route limitation.

Sitemap

Prestruct auto-generates sitemap.xml with:

404 Pages

Prestruct generates a 404 page with noindex robots directive:

<meta name="robots" content="noindex, nofollow, noarchive, nosnippet, noimageindex" />

This prevents 404 pages from appearing in search results.

Robots.txt

Two ways, one contract: prestruct never touches dist/robots.txt unless you opt in. Author your own in public/robots.txt (copied through untouched):

User-agent: *
Allow: /

Sitemap: https://example.com/sitemap.xml

Or generate one from config (robots: true = minimal allow-all + Sitemap line, robots: "<body>" = custom body with the Sitemap line auto-appended, robots: { body, sitemap: false } = custom body without the pointer). Both come from the robots key in ssr.config.js; details: Config Reference.

AI crawlers (AEO)

robots: { aeo: true } writes a per-bot policy instead of a catch-all: search-visibility crawlers are allowed, training crawlers are disallowed by default (aeo: { aiBots: 'allow' } flips that). The separation matters because the vendor tokens differ: OAI-SearchBot controls ChatGPT search results while GPTBot controls OpenAI training crawls; Claude-SearchBot vs ClaudeBot; Applebot vs Applebot-Extended. Google-Extended is a product token for Gemini/Vertex grounding that does not affect Google Search inclusion. Details: Config Reference.

Two honest limits, from vendor documentation (2026):

What does move answer-engine visibility, per the same documentation: public crawlable HTML (prestruct prerenders every route, so this is already handled), stable canonicals, accurate titles/descriptions, visible author/date info, schema.org types that match visible content (Article, Person/ProfilePage, BreadcrumbList – see Structured Data), and not accidentally blocking resource URLs. FAQ rich results were retired May 2026; de-prioritize FAQPage markup unless the page is genuinely Q&A.

Security Headers

Prestruct sites on Cloudflare Pages get security headers automatically:

Validation

Use these tools to verify SEO:

Gotchas & Troubleshooting

Duplicate Meta Tags

If you see duplicate <title> or <meta name="robots"> tags, check your public/index.html for pre-existing meta tags. Prestruct’s inject-brand.js adds meta tags dynamically - remove duplicate meta from your base HTML.

404 Pages Not Indexed

Prestruct automatically adds noindex directives to 404 pages to prevent them from appearing in search results:

<meta name="robots" content="noindex, nofollow, noarchive, nosnippet, noimageindex" />

This is correct behavior - don’t remove it unless you want 404s indexed.

Trailing Slash Mismatch

If your canonical URL has a trailing slash but users access without (or vice versa), you may see duplicate content warnings. Choose one style in your route definitions and stay consistent.

Next steps