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

189 lines
4.4 KiB
Markdown

# 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
```html
<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
```typescript
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:
```typescript
// 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:
```typescript
export async function generateMetadata({ params }): Promise<Metadata> {
return {
alternates: {
canonical: `https://example.com/${params.slug}`,
},
}
}
```
## Redirects
CMS-managed redirects:
```typescript
// next.config.ts
async redirects() {
const redirects = await client.fetch(`
*[_type == "redirect" && isEnabled == true]{
source,
destination,
permanent
}
`)
return redirects
}
```
## Performance
[Core Web Vitals](https://web.dev/articles/defining-core-web-vitals-thresholds) 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)
```typescript
// 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:
```typescript
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.