Files
theater-ziefen-website/.agents/skills/seo-aeo-best-practices/references/technical-seo.md
T
johannes.gasser 57af0b8386
Build and Deploy / build-and-deploy (push) Successful in 2m53s
add skills
2026-05-18 08:39:42 +02:00

4.4 KiB

Technical SEO Checklist

Essential technical SEO elements for modern web applications.

Table of Contents

  • Metadata
  • Sitemaps
  • Canonical URLs
  • Redirects
  • Performance
  • Robots.txt
  • International SEO

Metadata

Title Tags

  • Unique per page
  • 50-60 characters
  • Primary keyword near the beginning
  • Brand name at the end (optional)

Meta Descriptions

  • Unique per page
  • 150-160 characters
  • Include call-to-action
  • Contain relevant keywords

Open Graph

<meta property="og:title" content="Page Title" />
<meta property="og:description" content="Description" />
<meta property="og:image" content="https://example.com/image.jpg" />
<meta property="og:url" content="https://example.com/page" />
<meta property="og:type" content="article" />

Sanity + Next.js Implementation

export async function generateMetadata({ params }): Promise<Metadata> {
  const { data } = await sanityFetch({
    query: PAGE_QUERY,
    stega: false,  // Critical: no stega in metadata
  })
  
  return {
    title: data.seo?.title || data.title,
    description: data.seo?.description,
    openGraph: {
      images: data.seo?.image ? [{
        url: urlFor(data.seo.image).width(1200).height(630).url(),
        width: 1200,
        height: 630,
      }] : [],
    },
    robots: data.seo?.noIndex ? 'noindex' : undefined,
  }
}

Sitemaps

Dynamic sitemap from CMS content:

// app/sitemap.ts
import { MetadataRoute } from 'next'

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const pages = await client.fetch(`
    *[_type in ["page", "post"] && defined(slug.current) && seo.noIndex != true]{
      "url": select(
        _type == "page" => "/" + slug.current,
        _type == "post" => "/blog/" + slug.current
      ),
      _updatedAt
    }
  `)
  
  return pages.map(page => ({
    url: `https://example.com${page.url}`,
    lastModified: new Date(page._updatedAt),
    // Note: changeFrequency and priority are largely ignored by Google
    // but may be used by other search engines
  }))
}

Canonical URLs

Prevent duplicate content issues:

export async function generateMetadata({ params }): Promise<Metadata> {
  return {
    alternates: {
      canonical: `https://example.com/${params.slug}`,
    },
  }
}

Redirects

CMS-managed redirects:

// next.config.ts
async redirects() {
  const redirects = await client.fetch(`
    *[_type == "redirect" && isEnabled == true]{
      source,
      destination,
      permanent
    }
  `)
  return redirects
}

Performance

Core Web Vitals impact rankings:

  • LCP (Largest Contentful Paint): < 2.5s
  • INP (Interaction to Next Paint): < 200ms
  • CLS (Cumulative Layout Shift): < 0.1

Image Optimization (Next.js example)

  • Use next/image with Sanity URL builder
  • Serve WebP/AVIF formats
  • Implement LQIP blur placeholders
  • Set explicit dimensions

Font Loading (Next.js example)

// Prevent layout shift
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'], display: 'swap' })

Robots.txt

# public/robots.txt
User-agent: *
Allow: /
Disallow: /api/
Disallow: /studio/

# AI crawlers — allow or block based on your content strategy
# Uncomment to block specific AI crawlers:
# User-agent: GPTBot
# Disallow: /
# User-agent: ClaudeBot
# Disallow: /
# User-agent: PerplexityBot
# Disallow: /
# User-agent: Google-Extended
# Disallow: /

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

AI crawler considerations: Decide whether AI training crawlers should access your content. Blocking Google-Extended prevents AI training use while still allowing Google Search indexing. Review your policy regularly as this landscape evolves.

International SEO (hreflang)

For multi-language sites, implement hreflang tags to indicate language/region variants:

export async function generateMetadata({ params }: { params: Promise<{ lang: string; slug: string }> }): Promise<Metadata> {
  const { lang, slug } = await params
  return {
    alternates: {
      canonical: `https://example.com/${lang}/${slug}`,
      languages: {
        'en': `https://example.com/en/${slug}`,
        'de': `https://example.com/de/${slug}`,
        'x-default': `https://example.com/en/${slug}`,
      },
    },
  }
}

Include all language variants in sitemaps with hreflang annotations for proper indexing.