Developer Guide · Code Diffs

Common Programmatic SEO Code Mistakes & Fixes

Google SGE and core spam updates have raised the quality threshold for programmatic web pages. Monotonous layouts built only to catch long-tail search queries are demoted. Below is a guide illustrating common technical and structure-level mistakes, followed by before-and-after code blocks showing how to implement compliant Next.js, React, and HTML templates.

Visual Code Comparisons

❌ Bad (SpamBrain Trigger)Before
// apps/web/app/listing/[city]/page.tsx
// ❌ BAD: No canonical tag, generic descriptions, missing schema.org entities.
export default function CityPage({ params }: { params: { city: string } }) {
  return (
    <main>
      <h1>Services in {params.city}</h1>
      <p>Looking for services in {params.city}? We offer the best solutions...</p>
      {/* 80% boilerplate page layout follows */}
    </main>
  );
}
✅ Good (Compliant & Dynamic)After
// apps/web/app/listing/[city]/page.tsx
// ✅ GOOD: Dynamic metadata, unique descriptions, self-referencing canonicals, nested JSON-LD schema.
import { Metadata } from "next";

export async function generateMetadata({ params }): Promise<Metadata> {
  const canonical = `https://pseolint.dev/listing/${params.city}`;
  return {
    title: `Local Services in ${params.city} | Certified Providers`,
    description: `Find top-rated local services in ${params.city}. Verified local provider listings, pricing estimates, and real user reviews.`,
    alternates: { canonical }
  };
}

export default function CityPage({ params }) {
  const schema = {
    "@context": "https://schema.org",
    "@type": "LocalBusiness",
    "name": `Certified Service Providers in ${params.city}`,
    "description": `Top-rated verified provider listings in ${params.city}.`,
    "address": { "@type": "PostalAddress", "addressLocality": params.city }
  };

  return (
    <main>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
      />
      <h1>Services in {params.city}</h1>
      {/* Dynamic, dense, localized data tables and reviews */}
    </main>
  );
}

Detailed Deficit Deep-Dive

1. The Entity-Swap Trap (Doorway Pages)

Critical Error

Creating 10,000 pages where the only difference is a swapped city name or keyword token (e.g. 'Web development in Boston' vs 'Web development in Denver') is the easiest way to trigger a SpamBrain doorway-page penalty. Google expects genuine local entity details, address citations, or specialized data on each page.

Remedy: Inject unique local API data, named practitioners, custom price points, and localized guides.

2. Missing self-referential canonical tags

Major Warning

If you omit the canonical tag or mistakenly point all generated pages to the category root or homepage, Google will consolidate them. Googlebot will pick one representative URL, index it, and drop the remaining 99.9% of your pages under the 'Duplicate, Google chose different canonical' label.

Remedy: Always ensure every dynamic route returns a unique, self-referencing canonical URL.

3. High Boilerplate-to-Content Ratio

Major Warning

If 85% of your page's words live in the navigation bar, sidebars, related links, and the footer, Google classifies the URL as near-duplicate boilerplate. Programmatic pages must have at least 300 words of substantive, template-unique text that doesn't repeat across sibling pages.

Remedy: Keep boilerplate ratio under 60% by stripping filler blocks and expanding page-specific details.

4. No Machine-Readable Structured Data (Schema)

Optimization Gap

Search engine AI Overviews (SGE) rely heavily on structured entities to formulate citations. If your pages lack FAQPage, Product, or HowTo JSON-LD schemas, you are missing out on rich snippets and AI recommendations.

Remedy: Inject valid nested JSON-LD objects matching the page's primary intent.

Sources