SEO for Developers Is Mostly Wrong | What Actually Ranks in 2026

There'sa lot of SEO advice around that isn't updated.

Add meta keywords. Use dynamic rendering. Block pages with robots.txt to de-index them. Optimise for First Input Delay.

Every single one of those is wrong in 2026.

Google replaced FID with Interaction to Next Paint in March 2024. Dynamic rendering is officially deprecated. The meta keywords tag has been ignored for over a decade. And robots.txt has never controlled indexing.

Meanwhile, AI Overviews launched and rewrote the rules. Impressions on content are up 49% since launch. Click-through rates dropped nearly 30%. And 54% of AI Overview citations now come from pages that already rank organically.

The playbook changed. Most developers didn't notice.

I spent a week going through Google's actual documentation, the BrightEdge data, the Next.js metadata API, and Core Web Vitals thresholds. This is what I found: the stuff that actually moves the needle, with code you can ship today.

TL;DR

INP replaced FID. The threshold is 200ms. LCP needs to be under 2.5 seconds. CLS under 0.1. Dynamic rendering is deprecated. Use SSR or SSG. AI Overviews are eating 30% of your clicks. The nosnippet meta tag is your opt-out. And there's a prompt at the bottom to audit your own site with AI.

The Three Numbers That Matter

Google uses three Core Web Vitals to evaluate your page. Not PageSpeed scores. Not Lighthouse numbers from a single run. Real user data, measured at the 75th percentile across all visits.

LCP (Largest Contentful Paint): 2.5 seconds or less. This measures how fast the biggest visible element loads. Usually a hero image or heading. If your LCP image is lazy-loaded, that's probably why your score is bad.

INP (Interaction to Next Paint): 200 milliseconds or less. This replaced First Input Delay in March 2024. FID only measured the delay of the first click. INP measures the worst interaction latency across the entire page lifecycle. Every click, tap, and keypress counts now.

CLS (Cumulative Layout Shift): 0.1 or less. This measures how much your content jumps around. Images without dimensions, dynamically injected banners, and web fonts swapping in are the usual culprits.

The critical difference from 2020: Google now uses field data (real users) for ranking, not lab data (your Lighthouse run). You can score 100 in Lighthouse and still fail Core Web Vitals in Search Console.

Check your real numbers in Google Search Console under the Core Web Vitals report.

What Google Actually Penalises

The "Page Experience" signal is no longer a single ranking system. Google broke it into components. Core Web Vitals still matter, but the penalties have shifted to specific spam policies introduced in March 2024.

Scaled content abuse. Generating massive amounts of low-value content to manipulate rankings. Whether it's AI-generated or human-written doesn't matter. If it's low quality at scale, it gets hit.

Site reputation abuse. Publishing third-party pages on a reputable domain to exploit that domain's authority. Think sponsored coupon pages or low-quality review sections that the host site barely oversees.

Expired domain abuse. Buying an expired domain with existing authority and repurposing it for low-quality content.

Back-button hijacking. This one is new. Google added it to the malicious practices policy with enforcement starting June 2026. If your site manipulates browser history to trap users, that's now a spam violation.

None of these are things most developers do intentionally. But if you're working on a site that does any of them, fix it before June.

The Technical Checklist

These are the things developers actually control that most get wrong.

Canonical URLs

Every indexable page needs a single, absolute canonical URL.

<link rel="canonical" href="https://example.com/blog/seo-guide" />

Common mistakes: using relative paths, having multiple canonical tags on one page, or pointing the canonical to a URL that redirects somewhere else. All of these send conflicting signals.

robots.txt Is Not for De-Indexing

This is the most common misconception I see. robots.txt controls crawling. It does not control indexing. If you block a page with Disallow, Google can still index it if other pages link to it. It just can't crawl it to see your noindex tag.

Use robots.txt to manage crawl budget and prevent server overload. Use noindex to actually remove pages from the index.

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

The page must remain crawlable for Google to see the noindex directive. Blocking it in robots.txt and adding noindex is contradictory.

Also, never block your CSS or JavaScript assets. If Google can't render the page, it can't understand it.

Structured Data

Implement JSON-LD for relevant schema types. Article, Product, FAQ, HowTo. Make sure all required fields are present or you won't be eligible for rich results.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "SEO for Developers Is Mostly Wrong",
  "datePublished": "2026-05-12",
  "dateModified": "2026-05-12",
  "author": {
    "@type": "Person",
    "name": "Alex Dunlop"
  }
}
</script>

Test it with Google's Rich Results Test before you deploy.

Sitemaps

Keep XML sitemaps under 50,000 URLs or 50MB. Use a sitemap index file for larger sites. Don't include noindexed URLs, redirected URLs, or non-canonical URLs. Update automatically on deploy and submit through Search Console.

Next.js SEO in 2026

If you're using the App Router, you have everything you need built in. Stop manually placing meta tags in layout files.

generateMetadata

This is the right way to handle per-page metadata in Next.js.

export async function generateMetadata({ params }) {
  const post = await getPost(params.slug);
  const url = `https://alexdunlop.com/notes/${params.slug}`;
 
  return {
    title: `${post.title} | Alex Dunlop`,
    description: post.excerpt,
    alternates: { canonical: url },
    robots: { index: true, follow: true },
    openGraph: {
      title: post.title,
      url,
      images: [`https://alexdunlop.com/og/${params.slug}.png`],
    },
  };
}

This gives you titles, descriptions, canonicals, robots directives, and Open Graph tags in one place. Dynamic per route. Type-safe.

Dynamic OG Images

Use ImageResponse from next/og to generate social cards at the edge.

import { ImageResponse } from "next/og";
 
export const runtime = "edge";
 
export function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const title = searchParams.get("title") ?? "Alex Dunlop";
 
  return new ImageResponse(
    (
      <div
        style={{
          display: "flex",
          fontSize: 64,
          background: "#0a0a0a",
          color: "#fafafa",
          width: "100%",
          height: "100%",
          alignItems: "center",
          justifyContent: "center",
          padding: 48,
        }}
      >
        {title}
      </div>
    ),
    { width: 1200, height: 630 }
  );
}

Every page gets a unique social card. No Figma. No Canva. No manual exports.

SSR vs SSG vs ISR

Use Static Site Generation or Incremental Static Regeneration for content that doesn't change often. Blog posts, documentation, landing pages. Fastest possible load times.

Use Server-Side Rendering for pages with dynamic or personalised content. Dashboards, e-commerce with live inventory, user profiles.

Never use pure client-side rendering for anything that needs to be indexed. Google's crawler can run JavaScript, but it's slower and less reliable than receiving fully-formed HTML.

Dynamic rendering (serving different content to bots vs users) is officially deprecated by Google. It was always a workaround. Use real SSR or SSG.

Performance That Ranks

Images

Use AVIF as your primary format with a WebP fallback. AVIF gives you 10-15% smaller files than WebP according to Cloudinary's State of Visual Media Report.

<picture>
  <source type="image/avif" srcset="/hero.avif" />
  <source type="image/webp" srcset="/hero.webp" />
  <img
    src="/hero.jpg"
    alt="Dashboard showing Core Web Vitals metrics"
    width="1200"
    height="630"
    fetchpriority="high"
  />
</picture>

Never lazy-load above-the-fold images. That includes your LCP element. Add fetchpriority="high" to signal its importance to the browser.

Apply loading="lazy" only to images below the fold.

Fonts

Use font-display: swap to keep text visible during font loading. Then prevent layout shifts when the font swaps in using CSS metric overrides.

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter.woff2") format("woff2");
  font-display: swap;
  ascent-override: 90%;
  descent-override: 22%;
  size-adjust: 107%;
}

The ascent-override, descent-override, and size-adjust properties match the fallback font's metrics to the web font. When the swap happens, nothing jumps.

Resource Hints

Preconnect to critical third-party domains. Preload resources the browser discovers late.

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preload" as="image" href="/hero.avif" fetchpriority="high" />

Bundle Size

The median JavaScript payload on mobile hit 558 KB in 2024 and it's still growing. That JavaScript has to be downloaded, parsed, and executed. While it runs, the main thread is blocked. Users click buttons and nothing happens.

This is what kills INP. Large bundles block the main thread, which delays every interaction. If your INP is bad, the first place to look is your JavaScript bundle.

AI Overviews Changed Everything

This is the section most developers aren't paying attention to.

Google's AI Overviews generate answers directly on the search results page. A one-year study by BrightEdge found that impressions on all content surged over 49% since AI Overviews launched. But click-through rates to actual websites dropped nearly 30% since May 2024.

Users are getting their answers without clicking through. Your content is being used, but you're not getting the traffic.

The overlap between content cited in AI Overviews and pages ranking organically grew from 32% to 54%. If you rank well in traditional search, you're increasingly likely to be cited in AI answers. But that citation might replace the click rather than drive one.

How to Rank in AI Overviews

Rank organically first. There's a 54% overlap now between organic rankings and AI Overview citations. The foundation hasn't changed.

Lead with facts. AI Overviews pull "fact-first" content. Don't build up to the answer. Put the answer at the top of each section, then explain. Every H2 should be independently answerable.

Use structured data. Article schema with correct datePublished and dateModified. HowTo schema for tutorials. FAQ schema for question-based content. This removes ambiguity for the AI.

Cover intent comprehensively. Break topics into clear, labeled sections. An article about Core Web Vitals should have separate sections for "What is LCP?", "Good LCP Score", "What is INP?". Each section should provide direct, factual information.

The Opt-Out

If you don't want your content used in AI Overviews, the nosnippet meta tag prevents it.

<meta name="robots" content="nosnippet" />

This also removes all text snippets from your regular search listings. It's a blunt tool but it works.

Myths That Need to Die

"Use dynamic rendering for JavaScript sites." Deprecated. Google's own documentation calls it a workaround, not a long-term solution. Use SSR or SSG.

"Block pages in robots.txt to remove them from Google." Wrong. robots.txt controls crawling, not indexing. A page blocked by robots.txt can still be indexed if other sites link to it. Use noindex and keep the page crawlable.

"Page Experience is a major standalone ranking system." It's not. Core Web Vitals matter as a competitive factor, but they don't override content quality and links. You can't compensate for mediocre content with a perfect Lighthouse score.

"Add more meta tags to boost rankings." The meta keywords tag has been ignored by Google for over a decade. The title tag matters for display and relevance. The meta description affects click-through rate from search results but doesn't directly boost rank. The meta robots tag controls indexing. That's it.

The Prompt

Here's the part that makes this actionable. Copy this prompt, paste your website URL, and run it in any AI coding agent or browser-based AI.

Audit the SEO of [YOUR_URL]. Fetch the page, inspect the HTML,
and give me specific findings with exact code fixes.
 
1. Core Web Vitals
   - What is the LCP element? Is it lazy-loaded, or is it a video
     without a poster image?
   - Are there images or videos without explicit width/height?
   - Are there third-party iframes or heavy scripts blocking the
     main thread?
 
2. Meta tags & indexability
   - Does the page have a unique title under 60 chars?
   - A meta description under 160 chars?
   - A canonical URL? Does it match the actual serving URL
     (check www vs non-www)?
   - An explicit robots meta tag?
 
3. Open Graph & social tags
   - Are og:title, og:description, og:image, and twitter:card set?
   - Is the OG image URL valid and properly sized (1200x630)?
 
4. Structured data
   - Is there JSON-LD on the page? If not, write the correct schema
     for this page type (Article, Person, WebSite, Product, etc.)
     with all required fields.
 
5. Heading hierarchy
   - Is there exactly one H1?
   - Do H2s and H3s follow a logical outline?
 
6. Images
   - Do all images have descriptive alt text (not empty, not
     "image", not keyword-stuffed)?
   - Are filenames descriptive?
   - Are modern formats (AVIF/WebP) being served?
 
7. Internal links
   - Does the page link to other pages on the same domain with
     descriptive anchor text?
   - Are there orphaned pages with no internal links pointing
     to them?
 
8. Performance
   - Are there preconnect/dns-prefetch hints for third-party
     domains?
   - Is font-display: swap being used?
   - Are above-the-fold images using fetchpriority="high"?
   - Are below-the-fold images and iframes using loading="lazy"?
 
9. AI Overview readiness
   - Does each H2 section open with a direct factual statement
     that could be extracted as a standalone answer?
   - Is there structured data that gives AI explicit facts
     (dates, names, numbers) to cite?
 
For each issue, give me the exact code fix. Prioritise by impact
on Core Web Vitals first, then indexability, then AI readiness.

Paste your deployed URL alongside this prompt. You'll get a prioritised list of fixes you can ship in an afternoon.

Next Steps

Run the audit prompt against your own site. Fix the LCP image loading, add generateMetadata if you're on Next.js, and check your structured data with the Rich Results Test.

The gap between developers who understand modern SEO and those cargo-culting 2020 advice is wide. Closing it takes an afternoon.