The blog had 1,200 posts and paginated archives. A redesign swapped numbered pages for a "Load more" button and canonicalised every ?page=N URL to page 1. Six months later, about 900 older posts had dropped out of the index. They weren't removed or noindexed. Crawlers just had no way to reach them any more.
Pagination SEO didn't go away when rel="next" stopped mattering. It just stopped being about tags.
TL;DR
- Google said in 2019 that it hadn't used
rel=next/prevas an indexing signal for years. Leaving the tags in is harmless, but they don't fix anything. - What matters: every page in a series is a crawlable URL, linked with real
<a href>, self-canonical, indexable and not infinite. - "Load more" and infinite scroll without paginated URLs hide deep items from crawlers.
- My opinion: canonicalising page 2+ to page 1 is the most common pagination mistake, and it's still in a lot of SEO plugins' advice.
Check 1: each page has its own URL
/blog?page=3 or /blog/page/3/ must return page 3 when fetched directly, with no cookies or JavaScript state. If page 3 only exists after clicking "Load more" twice, crawlers will never see it.
curl -s https://example.com/blog/page/3/ | grep -oE '<a [^>]*href="/blog/[^"]+"' | head You should see links to posts that aren't on page 1.
Check 2: pages are linked with real anchors
Crawlers follow <a href>. They don't click buttons.
<!-- crawlable --> <a href="/blog/page/4/">Next</a> <!-- not crawlable --> <button onclick="loadMore()">Load more</button> If you want infinite scroll for users, keep a paginated URL behind it: the button loads page 4 and is (or sits next to) a real link to /blog/page/4/, and the URL updates with history.pushState as the user scrolls. Users get the smooth version, crawlers get the links.
Check 3: each page is self-canonical
<!-- on /blog/page/3/ --> <link rel="canonical" href="https://example.com/blog/page/3/"> Not page 1. Pointing page 3's canonical at page 1 says "these are duplicates, ignore page 3", and the links on page 3 can lose their value as a discovery path. They're not duplicates: different items, different links. Canonical mistakes in general are covered in How to check a canonical tag.
The one legitimate exception: a "view all" page that loads quickly can be the canonical for the series.
Check 4: pages aren't noindexed
Some setups add noindex to page 2+ to "avoid thin content". Over time, a noindexed page tends to be crawled less, and its links followed less, which brings back the deep-items problem. If you don't want page 7 to rank, that's fine. It won't, because it isn't the best answer for any query. Leave it indexable. Noindex can also hide in an HTTP header, as described in How to find a noindex in the X-Robots-Tag header.
Check 5: the series ends
Requesting ?page=9999 should return a 404, not an empty listing with 200 (a soft 404) or a redirect to page 1. Also watch for filter and sort parameters multiplying the series: ?page=3&sort=price&color=red combinations can create a near-infinite URL space.
A script that runs all five checks
# pip install requests beautifulsoup4 import sys, requests from bs4 import BeautifulSoup from urllib.parse import urljoin def page_url(base, n): return base if n == 1 else f"{base.rstrip('/')}/page/{n}/" # adjust to your pattern def inspect(url): r = requests.get(url, timeout=20, headers={"User-Agent": "Mozilla/5.0"}) s = BeautifulSoup(r.text, "html.parser") canon = s.find("link", rel="canonical") robots = s.find("meta", attrs={"name": "robots"}) links = {urljoin(url, a["href"]) for a in s.find_all("a", href=True)} return r.status_code, (canon or {}).get("href"), (robots or {}).get("content", ""), \ r.headers.get("X-Robots-Tag", ""), links base = sys.argv[1] for n in (2, 3): url = page_url(base, n) code, canon, robots, xrt, links = inspect(url) issues = [] if code != 200: issues.append(f"status {code}") if canon and canon.rstrip("/") != url.rstrip("/"): issues.append(f"canonical -> {canon}") if "noindex" in (robots + xrt).lower(): issues.append("noindex") if page_url(base, n + 1).rstrip("/") not in {l.rstrip("/") for l in links}: issues.append("no <a href> to next page") print(f"{'OK ' if not issues else 'BAD'} {url} {issues}") code, *_ = inspect(page_url(base, 9999)) print(f"{'OK ' if code == 404 else 'BAD'} page 9999 returns {code} (want 404)") python pagination_check.py https://example.com/blog/ How it connects to orphan pages
When pagination breaks, deep items become orphans: in the sitemap, but with no crawlable internal links. That makes How to find orphan pages by comparing your sitemap to internal links the best follow-up check after any listing redesign. Your server logs will confirm it from the other side. If crawlers stop requesting /page/N/ URLs after a redesign, that's the signal (see the crawl budget and logs post).
Keep watching after redesigns
Pagination usually breaks during front-end rewrites, not content changes. Add the script to the same post-deploy checks as the raw vs rendered HTML diff, because "Load more" problems are often a rendering problem underneath. For ongoing tag monitoring across many pages, a service like seotto.com alerts you when canonicals or robots directives change on templates you didn't touch on purpose.
My take
Pagination exists for crawlers as much as for people. It's often the only internal path to older content. Treat page 2+ as real, indexable, self-canonical pages with real links, and most pagination "SEO problems" disappear without any special tags.
Over to you
Infinite scroll, "Load more" or numbered pages: what does your site use, and did you keep crawlable paginated URLs behind it? I'm also curious whether anyone still sees a measurable effect from keeping rel=next/prev in place.

