SEO is usually treated as a marketing task, but a large part of it is decided in the markup. Marketers pick the keywords; the frontend decides whether a crawler can find, read and understand the page at all. If your <h1> is a <div>, your title is "React App" and your content only appears after a client-side fetch, no amount of content strategy will fix that.
This post covers the SEO work that belongs to you as a frontend developer — with concrete code, not theory.
1. One <h1> and a real heading outline
Headings are the table of contents of your page. Crawlers (and screen readers) build a document outline from them, so the order matters more than the size.
<h1>Frontend Interview Questions</h1>
<h2>HTML</h2>
<h3>What is validation?</h3>
<h2>CSS</h2>
<h3>What is specificity?</h3>
Rules that actually matter:
- One
<h1>per page, describing what the page is about. - Never skip levels — no
<h2>followed directly by<h4>. - Never pick a heading level for its font size. Style it with CSS instead.
- Headings are not decoration: a "Subscribe" button label should not be an
<h2>.
2. Title and meta description
The <title> is still one of the strongest on-page signals, and the meta description is what a user reads in the search results before deciding to click.
<title>Core Web Vitals Explained: LCP, INP and CLS — iFace</title>
<meta
name="description"
content="What LCP, INP and CLS measure, what the thresholds are, and how to fix the most common causes in the frontend."
/>
Practical limits:
- Title: roughly 50–60 characters before Google truncates it. Put the important words first, brand name last.
- Description: roughly 140–160 characters. It is not a ranking factor, but it is a click-through factor.
- Every page needs its own. Duplicated titles across a site are one of the most common audit findings.
3. Semantic HTML and landmarks
A page built entirely out of <div> renders identically for a user and much worse for a machine. Semantic elements give a crawler free structural information:
<header>...</header>
<nav aria-label="Main">...</nav>
<main>
<article>
<h1>...</h1>
<p>...</p>
</article>
</main>
<aside>...</aside>
<footer>...</footer>
Two rules that solve most cases:
- A thing you click that navigates is an
<a href>. A<div onClick={() => router.push(...)}>is invisible to a crawler — it will not follow it. - A thing you click that performs an action is a
<button>.
This is the same set of decisions you make for accessibility, which is why accessible sites tend to be well-indexed sites. If you want a refresher on the underlying markup rules, the frontend interview questions collection covers validation, semantics and selectors question by question.
4. Images
Images are where SEO and performance overlap the most.
<img
src="/hero.webp"
alt="Chrome DevTools showing a Lighthouse performance report"
width="1200"
height="630"
loading="lazy"
decoding="async"
/>
altdescribes the image content. It is what image search indexes and what a screen reader announces. Decorative image? Usealt=""— an empty alt is correct, a missing alt is not.widthandheightare not obsolete. They let the browser reserve space and prevent layout shift (see CLS below).loading="lazy"for everything below the fold — but never for your largest above-the-fold image, or you delay your LCP.- Modern formats (WebP, AVIF) usually cut file size 30–50% at the same visual quality.
5. Links and anchor text
Anchor text tells search engines what the destination page is about.
<!-- weak -->
<a href="/post/nextjs-seo-checklist">click here</a>
<!-- strong -->
<a href="/post/nextjs-seo-checklist">Next.js SEO checklist</a>
Also worth knowing:
- Internal links spread authority. A page nothing links to is an orphan page — it may never be crawled at all.
rel="noopener noreferrer"ontarget="_blank"links is a security habit, not an SEO one, but do it anyway.rel="nofollow"tells engines not to pass authority. Use it for paid or untrusted links only — not for your own pages.
6. Canonical URLs
The same content reachable at several URLs (/post, /post/, ?utm_source=..., ?page=1) splits your ranking signals across duplicates. A canonical tag says which one is the real address:
<link rel="canonical" href="https://example.com/post/core-web-vitals" />
Use an absolute URL, and make sure the canonical of a page points to itself unless you deliberately want it consolidated elsewhere.
7. Open Graph and social previews
Not a ranking factor, but it decides whether a shared link looks like a card or like a bare URL:
<meta property="og:title" content="Core Web Vitals Explained" />
<meta property="og:description" content="LCP, INP and CLS for frontend developers." />
<meta property="og:image" content="https://example.com/og/core-web-vitals.png" />
<meta property="og:type" content="article" />
<meta name="twitter:card" content="summary_large_image" />
The image should be 1200×630 and hosted at an absolute URL.
8. Structured data (JSON-LD)
Structured data is how you tell a search engine what kind of thing a page is. It powers rich results — star ratings, FAQ accordions, recipe cards, breadcrumbs.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "SEO for Frontend Developers",
"datePublished": "2026-09-01",
"author": { "@type": "Person", "name": "iFace" },
"image": ["https://example.com/og/seo-frontend.png"]
}
</script>
JSON-LD is the format Google recommends — it lives in one block instead of being scattered through your markup as microdata attributes. Validate it with the Rich Results Test before you ship.
9. Rendering: what the crawler actually receives
This is the failure mode most specific to modern frontends. A pure client-side SPA ships an empty <div id="root"> and fills it in with JavaScript. Google can execute JavaScript, but it does so in a second pass with no guaranteed timing — and most other crawlers, including several AI ones, do not execute it at all.
- SSR / SSG — HTML arrives complete. Safest for anything you want indexed.
- CSR — content depends on JS execution. Fine for a dashboard behind a login, risky for a blog or a product page.
The quickest check you can run right now:
curl -s https://your-site.com/some-page | grep "a sentence from your content"
If that returns nothing, the crawler's first pass sees nothing either.
10. robots.txt and sitemap.xml
# robots.txt
User-agent: *
Allow: /
Disallow: /api/
Sitemap: https://example.com/sitemap.xml
The sitemap lists the URLs you want crawled, with a lastmod date so engines know what changed. It does not guarantee indexing — it just removes the excuse of not finding a page.
11. Core Web Vitals
Page experience is a real ranking signal, and all three metrics are frontend-owned: LCP (loading), INP (responsiveness) and CLS (visual stability). They deserve their own article — see Core Web Vitals explained for frontend developers.
How to verify your work
Shipping the markup is half the job; the other half is checking that it actually works in the wild.
- Lighthouse (built into Chrome DevTools) — lab data for performance, accessibility and basic SEO checks.
- Google Search Console — field data: what is indexed, what is excluded and why, plus real Core Web Vitals from actual users.
- Rich Results Test — validates your JSON-LD.
- View source, not DevTools' Elements panel — Elements shows the DOM after JavaScript ran; view-source shows what was actually delivered.
Those tools tell you what is broken on one page at a time. Doing it across an entire site — crawling every URL, comparing against competitors, deciding what to fix first — is where it gets tedious. This is the gap tools like RankBuddy fill: it runs the technical audit, maps competitors and keyword gaps, and tracks whether AI assistants like ChatGPT and Perplexity actually cite your site, then hands you a prioritized list instead of a raw dump of warnings. Useful if you would rather spend your time fixing markup than compiling spreadsheets about it.
Quick checklist
- Exactly one
<h1>, no skipped heading levels - Unique
<title>and meta description on every page - Semantic landmarks; navigation uses real
<a href> - Images have
alt,width,heightand a modern format - Descriptive anchor text; no orphan pages
- Self-referencing absolute canonical
- Open Graph tags with a 1200×630 image
- Valid JSON-LD for the page type
- Content present in server-rendered HTML
-
robots.txtandsitemap.xmlreachable and correct
Next: the framework-specific version of this list — the Next.js SEO checklist.