Home / Articles / Technical SEO Pitfalls in Modern JavaScript Frontends

This article is published in English.

Technical SEO Pitfalls in Modern JavaScript Frontends

Client-only rendering, flaky metadata, semantics, CWV, robots mistakes, and dynamic routes — fixes for engineering teams.

830 words

Nine technical SEO mistakes in modern JS apps

React, Vue, and Next make rich apps easy — and make it easy to ship HTML that crawlers struggle with. SEO is engineering, not only copywriting.

1. Client-only rendering

<div id="root"></div>
<script src="app.js"></script>

If the first response is an empty shell, some bots see nothing useful. Prefer SSR/SSG or hybrid rendering for public content.

2. Missing or flaky metadata

export default async function ProductPage() {
  const product = await getProduct();

  return (
    <main>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
    </main>
  );
}

Titles and descriptions must be stable per URL. Generating them only in useEffect is a classic footgun.

3. Ignoring semantic HTML

<title>My Application</title>
<meta name="description" content="Welcome to my app">

Headings, landmarks, and meaningful elements help both a11y and crawlers. Div soup hides structure.

4. Broken client navigation assumptions

export const metadata = {
  title: "Modern React Performance Guide",
  description:
    "Learn practical techniques for improving React application performance.",
};

Ensure each shareable view has a real URL and that soft navigation updates metadata.

5. No structured data

<div>
  <div>Article Title</div>
  <div>Article content</div>
</div>

JSON-LD for articles, products, and FAQs can improve rich results when it matches visible content.

6. Weak Core Web Vitals

<article>
  <header>
    <h1>Technical SEO Mistakes</h1>
  </header>

  <section>
    <p>Article content...</p>
  </section>
</article>

Huge JS bundles and late images tank LCP/INP. Code-split, optimize media, and measure field data.

7. Accidentally blocking crawlers

<Link href="/products/react-course">
  React Course
</Link>

Misconfigured robots.txt, noindex on prod, or auth walls on marketing pages wipe rankings overnight.

8. Dynamic routes without crawl strategy

<button onClick={() => navigate("/products/react-course")}>
  React Course
</button>
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Technical SEO Mistakes Developers Make",
  "author": {
    "@type": "Person",
    "name": "Developer"
  }
}

Sitemaps, stable slugs, and server-rendered detail pages matter when IDs are infinite.

9. Treating SEO as marketing later

const Chart = dynamic(() => import("./Chart"), {
  ssr: false,
});
<meta name="robots" content="noindex">

Bake metadata, rendering mode, and performance budgets into the definition of done.

Fixes worth repeating

Disallow: /
/products/item-123
/blog/article-name
/users/profile-name

Ship crawlable HTML, unique metadata, semantics, sitemaps, and performance budgets — then let content teams do their job on a foundation that works.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.

Prefer small examples readers can paste into a sandbox without a monorepo.