Category listings, blog archives and filtered views generate more URLs than the rest of your site combined — and most of them shouldn't be indexed. This is where crawl budget dies and where duplicate-content problems are actually born. The goal: crawlers reach every product/post, while junk URL permutations stay out of the index.
Pagination: real URLs, self-canonical
- Every page gets a real, linkable URL:
/blog/page/2or?page=2. Page 2 must exist as HTML the crawler can request. - Each page canonicals to itself — not to page 1. Canonicalizing page 2 to page 1 tells Google "page 2 is a duplicate", and everything linked only from page 2+ quietly falls out of discovery. This remains the most common pagination mistake.
rel="prev/next"was retired by Google in 2019 — what matters now is plain<a href>links between pages (numbered links help crawlers reach deep pages faster than next-only chains).- Titles should differ: append "— Page 2" to avoid duplicate-title noise.
In Next.js, path-based pages can be fully static:
// app/blog/page/[num]/page.tsx
export async function generateStaticParams() {
const pages = Math.ceil((await getPostCount()) / PAGE_SIZE);
return Array.from({ length: pages - 1 }, (_, i) => ({ num: String(i + 2) }));
}
Infinite scroll: pair it with real pages
"Load more" and infinite scroll are client-side — crawlers don't scroll. The robust pattern: keep paginated URLs as the crawlable backbone, update the address bar with the History API as the user scrolls (/page/3 when they reach chunk 3), and make each such URL render that chunk server-side on direct load. Users get the smooth feed; crawlers get pages.
Facets: the combinatorial explosion
A category with 6 filters × 10 values each yields millions of URL permutations. Classify facets into three tiers:
- Index-worthy — combinations with real search demand and stable inventory ("red running shoes", "apartments with balcony in Warsaw"). Give them clean static paths (
/running-shoes/red), unique titles/intros, self-canonical, in the sitemap. These are effectively programmatic SEO pages — apply the same unique-value bar. - Useful but not indexable — sort orders, price sliders, multi-select combos. Keep them as query params,
robots: { index: false, follow: true }, canonical to the base category. - Crawl traps — session params, infinite calendar/date combinations. Block in robots.txt so they don't eat crawl budget at all (noindex still requires crawling every URL to be seen).
Never let filters generate links the crawler can follow into tier-3 space — render those controls as buttons/forms, not <a href>.
Checklist:
- Paginated pages: real URLs, self-canonical, numbered
<a>links, distinct titles - No canonical-to-page-1; nothing reachable only via infinite scroll
- Facets classified into indexable / noindex,follow / robots-blocked tiers
- Index-worthy combos get static paths, unique content and sitemap entries
- Crawl-trap params never rendered as crawlable
<a href>links