# Technical SEO Checklist

**Meta-Description:** Komplette Technical SEO Checklist für 2026. Crawling, Indexierung, Site Structure und Performance-Optimierung für bessere Rankings.

**Keywords:** Technical SEO, SEO Checklist, Crawling, Indexierung, Site Structure, Page Speed, Mobile SEO, SEO Audit

---

## Einführung

**Technical SEO** bildet das Fundament für erfolgreiche Suchmaschinenoptimierung. Ohne saubere technische Basis nützt der beste Content wenig. Diese Checklist deckt alle wichtigen Aspekte ab – von **Crawling** bis **Performance**.

---

## Technical SEO Overview

```
┌─────────────────────────────────────────────────────────────┐
│              TECHNICAL SEO PYRAMID                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                    ┌─────────┐                             │
│                    │ Content │                             │
│                    │  & UX   │                             │
│                    └────┬────┘                             │
│               ┌─────────┴─────────┐                       │
│               │    On-Page SEO    │                       │
│               │  (Title, Meta,H1) │                       │
│               └─────────┬─────────┘                       │
│          ┌──────────────┴──────────────┐                  │
│          │      Site Architecture      │                  │
│          │  (URLs, Internal Links)     │                  │
│          └──────────────┬──────────────┘                  │
│     ┌───────────────────┴───────────────────┐             │
│     │         Crawling & Indexing           │             │
│     │  (robots.txt, sitemap, canonicals)    │             │
│     └───────────────────┬───────────────────┘             │
│  ┌──────────────────────┴──────────────────────┐          │
│  │            Server & Performance             │          │
│  │  (HTTPS, Speed, Core Web Vitals, Mobile)    │          │
│  └─────────────────────────────────────────────┘          │
│                                                             │
│  Priority Levels:                                          │
│  🔴 Critical - Must fix immediately                       │
│  🟡 Important - Fix soon                                  │
│  🟢 Nice to have - Optimize when possible                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

---

## Server & Security

```typescript
// lib/seo/audit/server.ts
interface ServerAuditResult {
  https: boolean;
  httpToHttpsRedirect: boolean;
  wwwRedirect: 'www' | 'non-www' | 'inconsistent';
  responseTime: number;
  serverHeaders: Record<string, string>;
  issues: string[];
}

async function auditServer(url: string): Promise<ServerAuditResult> {
  const issues: string[] = [];

  // HTTPS Check
  const https = url.startsWith('https://');
  if (!https) {
    issues.push('🔴 Site is not using HTTPS');
  }

  // HTTP to HTTPS Redirect
  const httpUrl = url.replace('https://', 'http://');
  const httpResponse = await fetch(httpUrl, { redirect: 'manual' });
  const httpToHttpsRedirect = httpResponse.status === 301 &&
    httpResponse.headers.get('location')?.startsWith('https://');

  if (!httpToHttpsRedirect) {
    issues.push('🔴 HTTP does not redirect to HTTPS');
  }

  // WWW Consistency
  const withWww = url.includes('www.');
  const testUrl = withWww
    ? url.replace('www.', '')
    : url.replace('://', '://www.');

  const wwwResponse = await fetch(testUrl, { redirect: 'manual' });
  const wwwRedirect = wwwResponse.status === 301 ? (withWww ? 'www' : 'non-www') : 'inconsistent';

  if (wwwRedirect === 'inconsistent') {
    issues.push('🟡 WWW and non-WWW versions not properly redirected');
  }

  // Response Time
  const start = Date.now();
  await fetch(url);
  const responseTime = Date.now() - start;

  if (responseTime > 500) {
    issues.push(`🟡 Server response time is slow: ${responseTime}ms`);
  }

  // Security Headers
  const response = await fetch(url);
  const serverHeaders: Record<string, string> = {};
  response.headers.forEach((value, key) => {
    serverHeaders[key] = value;
  });

  const requiredHeaders = [
    'strict-transport-security',
    'x-content-type-options',
    'x-frame-options'
  ];

  requiredHeaders.forEach(header => {
    if (!serverHeaders[header]) {
      issues.push(`🟢 Missing security header: ${header}`);
    }
  });

  return {
    https,
    httpToHttpsRedirect,
    wwwRedirect,
    responseTime,
    serverHeaders,
    issues
  };
}
```

```typescript
// middleware.ts - Security Headers
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const response = NextResponse.next();

  // Security Headers
  response.headers.set('X-DNS-Prefetch-Control', 'on');
  response.headers.set('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload');
  response.headers.set('X-Content-Type-Options', 'nosniff');
  response.headers.set('X-Frame-Options', 'SAMEORIGIN');
  response.headers.set('X-XSS-Protection', '1; mode=block');
  response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');

  // Permissions Policy
  response.headers.set(
    'Permissions-Policy',
    'camera=(), microphone=(), geolocation=(self), interest-cohort=()'
  );

  return response;
}
```

---

## Crawling & Indexing

```typescript
// app/robots.ts - Optimized robots.txt
import { MetadataRoute } from 'next';

export default function robots(): MetadataRoute.Robots {
  const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';

  return {
    rules: [
      {
        userAgent: '*',
        allow: '/',
        disallow: [
          '/api/',
          '/admin/',
          '/_next/',
          '/private/',
          '/*.json$',
          '/*?*',  // Query Parameter
          '/search?*'
        ]
      },
      {
        userAgent: 'Googlebot',
        allow: '/',
        disallow: ['/admin/', '/api/']
      },
      {
        // Block bad bots
        userAgent: ['AhrefsBot', 'SemrushBot', 'DotBot'],
        disallow: '/'
      }
    ],
    sitemap: `${baseUrl}/sitemap.xml`,
    host: baseUrl
  };
}

// app/sitemap.ts - Dynamic Sitemap
import { MetadataRoute } from 'next';
import { getAllPages, getAllPosts, getAllProducts } from '@/lib/content';

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';

  // Static Pages
  const staticPages: MetadataRoute.Sitemap = [
    {
      url: baseUrl,
      lastModified: new Date(),
      changeFrequency: 'daily',
      priority: 1.0
    },
    {
      url: `${baseUrl}/about`,
      lastModified: new Date(),
      changeFrequency: 'monthly',
      priority: 0.8
    },
    {
      url: `${baseUrl}/contact`,
      lastModified: new Date(),
      changeFrequency: 'yearly',
      priority: 0.5
    },
    {
      url: `${baseUrl}/blog`,
      lastModified: new Date(),
      changeFrequency: 'daily',
      priority: 0.9
    }
  ];

  // Dynamic Pages
  const pages = await getAllPages();
  const dynamicPages: MetadataRoute.Sitemap = pages.map(page => ({
    url: `${baseUrl}/${page.slug}`,
    lastModified: new Date(page.updatedAt),
    changeFrequency: 'monthly',
    priority: 0.7
  }));

  // Blog Posts
  const posts = await getAllPosts();
  const blogPosts: MetadataRoute.Sitemap = posts.map(post => ({
    url: `${baseUrl}/blog/${post.slug}`,
    lastModified: new Date(post.updatedAt),
    changeFrequency: 'weekly',
    priority: 0.8
  }));

  // Products
  const products = await getAllProducts();
  const productPages: MetadataRoute.Sitemap = products.map(product => ({
    url: `${baseUrl}/products/${product.slug}`,
    lastModified: new Date(product.updatedAt),
    changeFrequency: 'daily',
    priority: 0.9
  }));

  return [...staticPages, ...dynamicPages, ...blogPosts, ...productPages];
}
```

```typescript
// lib/seo/canonical.ts - Canonical URL Helper
export function getCanonicalUrl(path: string, locale?: string): string {
  const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';

  // Remove trailing slash
  const cleanPath = path.replace(/\/$/, '');

  // Remove query parameters for canonical
  const pathWithoutQuery = cleanPath.split('?')[0];

  // Add locale if needed
  if (locale && locale !== 'de') {
    return `${baseUrl}/${locale}${pathWithoutQuery}`;
  }

  return `${baseUrl}${pathWithoutQuery}`;
}

// Usage in page
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
  return {
    alternates: {
      canonical: getCanonicalUrl(`/blog/${params.slug}`)
    }
  };
}
```

---

## URL Structure

```typescript
// lib/seo/url-utils.ts
export function createSEOFriendlyUrl(title: string): string {
  return title
    .toLowerCase()
    .trim()
    // Umlaute ersetzen
    .replace(/ä/g, 'ae')
    .replace(/ö/g, 'oe')
    .replace(/ü/g, 'ue')
    .replace(/ß/g, 'ss')
    // Sonderzeichen entfernen
    .replace(/[^a-z0-9\s-]/g, '')
    // Mehrere Leerzeichen zu einem
    .replace(/\s+/g, ' ')
    // Leerzeichen zu Bindestrich
    .replace(/\s/g, '-')
    // Mehrere Bindestriche zu einem
    .replace(/-+/g, '-')
    // Max Länge
    .substring(0, 60);
}

// URL Audit
interface URLAuditResult {
  url: string;
  issues: string[];
  suggestions: string[];
}

export function auditURL(url: string): URLAuditResult {
  const issues: string[] = [];
  const suggestions: string[] = [];

  // Length check
  if (url.length > 75) {
    issues.push('🟡 URL is too long (> 75 characters)');
  }

  // Uppercase check
  if (url !== url.toLowerCase()) {
    issues.push('🟡 URL contains uppercase characters');
  }

  // Underscore check
  if (url.includes('_')) {
    issues.push('🟡 URL contains underscores (use hyphens instead)');
  }

  // Double slashes
  if (url.includes('//') && !url.startsWith('http')) {
    issues.push('🔴 URL contains double slashes');
  }

  // Query parameters
  if (url.includes('?')) {
    suggestions.push('Consider using clean URLs without query parameters');
  }

  // Trailing slash consistency
  if (!url.endsWith('/') && !url.includes('.')) {
    suggestions.push('Consider adding trailing slash for consistency');
  }

  return { url, issues, suggestions };
}
```

---

## On-Page SEO

```typescript
// lib/seo/audit/onpage.ts
interface OnPageAuditResult {
  title: { value: string; length: number; issues: string[] };
  metaDescription: { value: string; length: number; issues: string[] };
  h1: { count: number; value: string; issues: string[] };
  headings: { h2: number; h3: number; h4: number; issues: string[] };
  images: { total: number; withoutAlt: number; issues: string[] };
  links: { internal: number; external: number; broken: number; issues: string[] };
}

async function auditOnPage(html: string, url: string): Promise<OnPageAuditResult> {
  const parser = new DOMParser();
  const doc = parser.parseFromString(html, 'text/html');

  // Title
  const title = doc.querySelector('title')?.textContent || '';
  const titleIssues: string[] = [];
  if (!title) titleIssues.push('🔴 Missing title tag');
  else if (title.length < 30) titleIssues.push('🟡 Title too short (< 30 chars)');
  else if (title.length > 60) titleIssues.push('🟡 Title too long (> 60 chars)');

  // Meta Description
  const metaDesc = doc.querySelector('meta[name="description"]')?.getAttribute('content') || '';
  const metaDescIssues: string[] = [];
  if (!metaDesc) metaDescIssues.push('🔴 Missing meta description');
  else if (metaDesc.length < 120) metaDescIssues.push('🟡 Meta description too short');
  else if (metaDesc.length > 160) metaDescIssues.push('🟡 Meta description too long');

  // H1
  const h1Elements = doc.querySelectorAll('h1');
  const h1Issues: string[] = [];
  if (h1Elements.length === 0) h1Issues.push('🔴 Missing H1 tag');
  else if (h1Elements.length > 1) h1Issues.push('🟡 Multiple H1 tags found');

  // Heading Structure
  const h2Count = doc.querySelectorAll('h2').length;
  const h3Count = doc.querySelectorAll('h3').length;
  const h4Count = doc.querySelectorAll('h4').length;
  const headingIssues: string[] = [];
  if (h2Count === 0) headingIssues.push('🟡 No H2 headings found');

  // Images
  const images = doc.querySelectorAll('img');
  const imagesWithoutAlt = Array.from(images).filter(
    img => !img.getAttribute('alt')
  ).length;
  const imageIssues: string[] = [];
  if (imagesWithoutAlt > 0) {
    imageIssues.push(`🟡 ${imagesWithoutAlt} images missing alt text`);
  }

  // Links
  const links = doc.querySelectorAll('a[href]');
  const baseUrl = new URL(url);
  let internalLinks = 0;
  let externalLinks = 0;
  const linkIssues: string[] = [];

  links.forEach(link => {
    const href = link.getAttribute('href') || '';
    if (href.startsWith('/') || href.includes(baseUrl.hostname)) {
      internalLinks++;
    } else if (href.startsWith('http')) {
      externalLinks++;

      // Check for nofollow on external links
      const rel = link.getAttribute('rel') || '';
      if (!rel.includes('nofollow') && !rel.includes('sponsored')) {
        // Suggestion, not issue
      }
    }
  });

  return {
    title: { value: title, length: title.length, issues: titleIssues },
    metaDescription: { value: metaDesc, length: metaDesc.length, issues: metaDescIssues },
    h1: { count: h1Elements.length, value: h1Elements[0]?.textContent || '', issues: h1Issues },
    headings: { h2: h2Count, h3: h3Count, h4: h4Count, issues: headingIssues },
    images: { total: images.length, withoutAlt: imagesWithoutAlt, issues: imageIssues },
    links: { internal: internalLinks, external: externalLinks, broken: 0, issues: linkIssues }
  };
}
```

---

## Complete SEO Checklist

```typescript
// lib/seo/checklist.ts
export const technicalSEOChecklist = {
  server: [
    { id: 'https', priority: 'critical', item: 'HTTPS enabled', automated: true },
    { id: 'http-redirect', priority: 'critical', item: 'HTTP redirects to HTTPS (301)', automated: true },
    { id: 'www-redirect', priority: 'important', item: 'WWW/non-WWW consistency', automated: true },
    { id: 'response-time', priority: 'important', item: 'Server response < 500ms', automated: true },
    { id: 'security-headers', priority: 'nice', item: 'Security headers configured', automated: true }
  ],

  crawling: [
    { id: 'robots-txt', priority: 'critical', item: 'robots.txt exists and valid', automated: true },
    { id: 'sitemap', priority: 'critical', item: 'XML Sitemap exists', automated: true },
    { id: 'sitemap-submitted', priority: 'important', item: 'Sitemap submitted to Search Console', automated: false },
    { id: 'no-crawl-errors', priority: 'critical', item: 'No crawl errors in Search Console', automated: false },
    { id: 'canonical-tags', priority: 'critical', item: 'Canonical tags on all pages', automated: true }
  ],

  indexing: [
    { id: 'indexable', priority: 'critical', item: 'Important pages are indexable', automated: true },
    { id: 'noindex-correct', priority: 'important', item: 'noindex only on non-important pages', automated: true },
    { id: 'no-duplicate-content', priority: 'critical', item: 'No duplicate content issues', automated: true },
    { id: 'hreflang', priority: 'important', item: 'hreflang tags for multilingual sites', automated: true }
  ],

  urlStructure: [
    { id: 'url-readable', priority: 'important', item: 'URLs are human-readable', automated: true },
    { id: 'url-lowercase', priority: 'important', item: 'URLs are lowercase', automated: true },
    { id: 'url-hyphens', priority: 'nice', item: 'URLs use hyphens (not underscores)', automated: true },
    { id: 'url-length', priority: 'nice', item: 'URLs under 75 characters', automated: true },
    { id: 'no-parameters', priority: 'nice', item: 'Clean URLs without parameters', automated: true }
  ],

  onPage: [
    { id: 'title-tag', priority: 'critical', item: 'Unique title tag (50-60 chars)', automated: true },
    { id: 'meta-description', priority: 'critical', item: 'Meta description (150-160 chars)', automated: true },
    { id: 'h1-tag', priority: 'critical', item: 'Single H1 per page', automated: true },
    { id: 'heading-hierarchy', priority: 'important', item: 'Proper heading hierarchy', automated: true },
    { id: 'image-alt', priority: 'important', item: 'All images have alt text', automated: true },
    { id: 'internal-links', priority: 'important', item: 'Internal linking structure', automated: false }
  ],

  performance: [
    { id: 'lcp', priority: 'critical', item: 'LCP < 2.5s', automated: true },
    { id: 'inp', priority: 'critical', item: 'INP < 200ms', automated: true },
    { id: 'cls', priority: 'critical', item: 'CLS < 0.1', automated: true },
    { id: 'mobile-friendly', priority: 'critical', item: 'Mobile-friendly design', automated: true },
    { id: 'page-size', priority: 'important', item: 'Page size < 3MB', automated: true }
  ],

  structuredData: [
    { id: 'jsonld', priority: 'important', item: 'JSON-LD structured data', automated: true },
    { id: 'valid-schema', priority: 'important', item: 'Schema validates in Rich Results Test', automated: false },
    { id: 'breadcrumbs', priority: 'nice', item: 'Breadcrumb schema', automated: true }
  ]
};

// Generate Audit Report
export function generateSEOReport(results: Record<string, boolean>): string {
  let report = '# Technical SEO Audit Report\n\n';

  Object.entries(technicalSEOChecklist).forEach(([category, items]) => {
    report += `## ${category.charAt(0).toUpperCase() + category.slice(1)}\n\n`;

    items.forEach(item => {
      const status = results[item.id];
      const emoji = status ? '✅' : (item.priority === 'critical' ? '❌' : '⚠️');
      report += `${emoji} ${item.item}\n`;
    });

    report += '\n';
  });

  return report;
}
```

---

## Checklist Summary

| Category | Critical | Important | Nice to Have |
|----------|----------|-----------|--------------|
| **Server** | HTTPS, Redirects | Response time | Security headers |
| **Crawling** | robots.txt, Sitemap | Search Console | Crawl budget |
| **Indexing** | Canonical, No duplicates | hreflang | Coverage report |
| **URLs** | - | Readable, lowercase | Short URLs |
| **On-Page** | Title, Meta, H1 | Alt text, Headings | Schema |
| **Performance** | Core Web Vitals | Page size | Resource hints |

---

## Fazit

Technical SEO Checklist erfordert:

1. **Server-Basics**: HTTPS, Redirects, Security
2. **Crawling**: robots.txt, Sitemap, Canonical
3. **On-Page**: Title, Meta, Headings, Images
4. **Performance**: Core Web Vitals optimieren

Regelmäßige Audits sichern die technische Basis.

---

## Bildprompts

1. "SEO audit dashboard showing checklist items, green checkmarks"
2. "Technical SEO pyramid diagram, layered structure"
3. "Search Console crawl stats visualization, data charts"

---

## Quellen

- [Google Search Central](https://developers.google.com/search/docs)
- [Ahrefs Technical SEO Guide](https://ahrefs.com/blog/technical-seo/)
- [Moz Technical SEO](https://moz.com/learn/seo/technical-seo)
- [Web.dev SEO](https://web.dev/learn/seo/)
