# 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 ``` ### Sanity + Next.js Implementation ```typescript export async function generateMetadata({ params }): Promise { 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 { 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 { 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 { 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.