Infinite Scroll SEO
How to implement infinite scroll without losing your indexing — why Googlebot doesn't scroll, the tall-viewport render trick that flattens two pages into one, the paginated-URL + History API fix, and the ecommerce category-page case.
Infinite scroll loads more content as you scroll, instead of via numbered pages — and Googlebot never scrolls or clicks, so anything gated behind that action is invisible by default. Google renders in a very tall viewport (about 411×12,140px mobile, 1024×9,307px desktop) as a workaround, but that same tall viewport can trigger the scroll loader during rendering and fold two logical pages into one indexed URL — a failure mode where a 'not indexed' page is actually indexed as part of another. The fix is architectural: give every chunk a real, persistent, absolute URL (like ?page=2), link them with crawlable anchors, and update the address bar with the History API as the user scrolls. rel=next/prev is legacy (Google dropped it in 2019; Bing still supports it). On ecommerce category pages, back it all with sitemaps or a Merchant Center feed and verify in the URL Inspection Tool's rendered HTML. A production build also needs a real popstate/back-forward contract, distinct loading/error/end states, and deliberate accessibility — none of that comes for free just because the indexing fix is in place.
Evidence for this claim Google Search does not generally interact with scrolling controls, so infinite-scroll content needs crawlable paginated URLs. Scope: Current official or standards documentation. Confidence: high · Verified: Google: Lazy-loaded content Evidence for this claim The History API can update URLs for loaded page chunks without a full navigation. Scope: Current official or standards documentation. Confidence: high · Verified: MDN: History APITL;DR — Infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. loads more content as you scroll down, instead of making you click to page 2, page 3, and so on. The catch: GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. doesn’t scroll and doesn’t click. So if your products or articles only appear once a visitor scrolls, Google may never see them. The fix is to give every “page” of content a real URL of its own, so search engines have something to crawl even though they never touch your scroll.
What infinite scroll is
You’ve used it a hundred times without naming it. On a social feed, a shopping category, or a long article, you keep scrolling and more stuff keeps appearing — no “Next page” button, no page numbers. That’s infinite scroll: JavaScript watches how far you’ve scrolled and, as you near the bottom, quietly fetches and adds the next batch of content.
It feels seamless for people. The problem is that search engines aren’t people.
Why it’s risky for SEO
Google finds and reads your pages with an automated program called GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer.. Googlebot loads your page, but it does not behave like a human visitor:
- It doesn’t scroll down the page.
- It doesn’t click buttons.
So any content that only loads after someone scrolls (or clicks “Load more”) simply isn’t there as far as Googlebot is concerned. If your category page shows 24 products up front and loads the rest on scroll, Google may only ever see those first 24.
The one rule that keeps it safe
Here’s the whole trick in one sentence: every chunk of content needs its own real web address.
Instead of relying only on scrolling, a search-friendly setup also has plain,
crawlable pages behind the scenes — example.com/shoes?page=2,
?page=3, and so on — linked together with normal links Google can follow. The
infinite scroll is the nice experience for humans; the numbered URLs are the
safety net for search engines. Modern implementations even swap the address in
your browser bar as you scroll, so if you copy the URL you land back in the exact
same spot.
What most people get wrong
- “Google can render JavaScriptMaking sure search engines can crawl, render, and index content that depends on JavaScript. now, so it’ll figure it out.” Google can run your JavaScript — but it still won’t scroll or click to trigger the loader. Being able to render isn’t the same as taking action.
- “A ‘Load more’ button is safer than auto-scroll.” Only if that button is a real link to a real page. A button that just runs a click handler is invisible to Google too.
- “If a page isn’t indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed., Google is ignoring it.” With infinite scroll, “not indexed” sometimes means the content got merged into another page by accident — which is a different problem with a different fix.
Infinite scroll isn’t banned or penalized. Done right — with real URLs underneath — it’s completely fine. Want the mechanics of why two pages sometimes get indexed as one, plus the actual code pattern to implement it? Switch to the Advanced tab.
Evidence for this claim Google Search does not generally interact with scrolling controls, so infinite-scroll content needs crawlable paginated URLs. Scope: Current official or standards documentation. Confidence: high · Verified: Google: Lazy-loaded content Evidence for this claim The History API can update URLs for loaded page chunks without a full navigation. Scope: Current official or standards documentation. Confidence: high · Verified: MDN: History APITL;DR — GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. never scrolls and never clicks, so scroll-gated content is invisible by default. Google’s workaround is to render in a very tall viewport (roughly 411×12,140px mobile, 1024×9,307px desktop) — but that same height can trigger the scroll loader during renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., folding the next logical page into the current one so two pages get indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. as a single URL. The durable fix is architectural: persistent, absolute, per-chunk URLs (e.g.
?page=12), linked with crawlable anchors, with the History API updating the address bar as each chunk becomes primary.rel=next/rel=previs legacy for Google (dropped 2019) but still respected by Bing. On ecommerce PLPs, sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. or a Merchant CenterGoogle Merchant Center (GMC) is a free platform where retailers upload and manage product data so their products can appear across Google — Shopping, organic Search product grids, Images, Lens, and AI surfaces. Since 2020 it powers free (organic) product listings, not just paid Shopping ads. feed are a discovery backstop. Verify everything in the URL Inspection ToolA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version.’s rendered HTML.
First, a disambiguation
If you search “Google infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page.” you’ll hit results about Google’s own continuous scroll on its search results pages — a SERP featureSERP features are any element on a search results page beyond the classic ten blue links — featured snippets, People Also Ask, knowledge panels, sitelinks, image and video packs, AI Overviews, and structured-data-driven rich results. Google documents that losing rich-result eligibility doesn't affect ranking; their SEO relevance is CTR (they redistribute clicks). Some are unlocked by markup; most are purely algorithmic. Google turned on and then discontinued in mid-2024. That’s a Google-product UX decision and has nothing to do with how GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. crawls your site. This article is about the latter: infinite scroll as a loading pattern on your own pages, and whether Google can index what it loads.
The core constraint: Google doesn’t interact with your page
Everything here follows from one fact. Google’s own lazy-loading docs say the recommended patterns “don’t rely on user actions, such as scrolling or clicking, to load content, which is important as Google Search does not interact with your page.” The paginationPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does. doc says it even more plainly: “Google’s crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. don’t ‘click’ buttons and generally don’t trigger JavaScript functions that require user actions to update the current page contents.”
As I put it in my own JavaScript SEO guide: “Googlebot doesn’t take action on webpages. It’s not going to click things or scroll, but that doesn’t mean it doesn’t have workarounds. As long as content is loaded in the DOM without a needed action, Google will see it. If it’s not loaded into the DOM until after a click, then the content won’t be found.”
So infinite scroll that only triggers on a real scroll event is a content-discovery problem before it’s anything else.
Google’s workaround: a very tall viewport
Google doesn’t simulate scrolling. Instead it renders your page in an unusually tall viewport, so content a few screens down is already inside the rendered area without anyone scrolling. The earliest on-record hint of this was John Mueller’s 2017 note that “Googlebot renders with a very tall viewport, which skews some CSS (often images). Try in Chrome dev-tools, eg 9000px high viewport.”
The specific numbers I’ve documented: for mobile, Google loads the page at a screen size of 411×731 pixels and resizes the length to 12,140 pixels — “essentially, it becomes a really long phone with a screen size of 411×12140 pixels. For desktop, it does the same and goes from 1024×768 pixels to 1024×9307 pixels.” (I haven’t seen recent re-tests of those exact figures, and they may vary with page length; the original dimensions trace back to independent testing by SEO researcher JR Oakes.) The point isn’t the exact pixel count — it’s that Google fakes “seeing far down the page” with height, not with movement.
Treat both the exact pixel dimensions and the two-pages-merged behavior below as dated, implementation-specific observations rather than a stable platform contract — Google doesn’t publish an official spec for either number, and renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. behavior can change. Don’t assume your site behaves the same way; confirm current behavior for your own URLs with the rendered-HTML test in the next section instead of taking these figures as a guarantee.
The failure mode nobody explains: two pages indexed as one
A normal browser viewport stops after page one. Google's render viewport expands much taller, reaches the infinite-scroll trigger without a real user scroll, and appends page two into the same DOM. The merged DOM is then indexed as one URL instead of two separate pages.
© Patrick Stox LLC · CC BY 4.0 ·
Here’s where the tall viewport bites back. Because the render viewport is so tall,
the scroll-triggered loader can fire during rendering even though nothing
“scrolled” in the human sense — the sheer DOM height can be enough to satisfy an
IntersectionObserver or a scroll-position check. When that happens, the loader
appends the next logical page’s content into the current page’s render, and
Google indexes the merged result as a single URL.
I’ve diagnosed this several times. From my JavaScript SEOMaking sure search engines can crawl, render, and index content that depends on JavaScript. guide:
“Another issue I’ve seen with this setup is, occasionally, two pages get indexed as one. I’ve seen this a few times when people said they couldn’t get their page indexed. But I’ve found their content indexed as part of another page that’s usually the previous post from them.”
“My theory is that when Google resized the viewport to be longer, it triggered the infinite scroll and loaded another article in when it was rendering. In this case, what I recommend is to block the JavaScript file that handles the infinite scrolling so the functionality can’t trigger.”
John Mueller described the same mechanic from Google’s side in a 2022 office-hours session: Google renders with a high viewport, that “would trigger some amount of infinite scrolling,” and “we might have two or three of these pages loaded on one page with infinite scroll, but not everything.” (That office-hours quote is relayed via Search Engine Journal’s write-up, not confirmed against the primary recording.)
Two consequences fall out of this:
- There’s no guarantee of how much gets pulled in. Might be nothing extra, might be two or three pages, never reliably everything. Infinite scroll alone is not a dependable way to get deep content indexed.
- “Not indexed” can be a misdiagnosis. The missing page may not be missing at all — it may be indexed as part of an earlier URL. That needs a different fix than a normal indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. bug.
How to diagnose it
Use Search ConsoleGoogle's free tool for monitoring crawling, indexing, and search performance.’s URL Inspection ToolA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. and read the rendered HTML, not the raw source. Google’s docs are explicit: “You can use the URL Inspection Tool in Search Console to see if all content was loaded. Check the rendered HTML to make sure your content is in the rendered HTML by looking for it in URL Inspection Tool.” Search the rendered HTML for content you expect to be on page 1 only. If you find content from page 2 (or the next article) sitting inside page 1’s render, you’ve reproduced the merge bug.
You can also replicate the tall viewport locally: open Chrome DevTools, set a very tall custom viewport (Mueller’s suggestion was ~9000px), and load the page to see whether your loader fires with no scrolling.
The fix: paginated URLs + the History API
The durable fix is architectural, straight from Google’s current lazy-loading doc. To make infinite scroll indexable, “make sure your website supports paginated loading of these chunks”:
- “Give each chunk its own persistent, unique URL.”
- “Ensure that the content shown on each URL remains the same every time it’s
loaded in a browser” — Google suggests absolute page numbers like
?page=12. - “Avoid using relative elements like
?date=yesterdayin these URLs” — an address that returns different content each load is unusable as a canonical. - “Link sequentially to the individual URLs so that search engines can discover the
URLs in a paginated set” — real
<a href>links, not click handlers. - “When a new page chunk is loaded in response to the user scrolling, and it becomes the primary visible element for the user, update the displayed URL using the History API.”
That last point is the elegant part. history.pushState() / replaceState() swaps
the URL in the address bar as the user scrolls past each boundary — so the visible
URL always matches the primary content, and the user can refresh, share, and link to
exactly where they are. Meanwhile the crawlable ?page=N URLs exist independently, so
Google can reach every chunk directly whether or not the renderer ever triggers the
scroll.
Two implementation notes that matter:
- Use
IntersectionObserver(or native browser lazy-loading), not a rawscrolllistener. It performs far better (no scroll-thrash) and it’s the “load when visible” mechanism Google endorses for deferred content. - Keep the paginated set discoverable independently of the JS. Real anchors in the
DOM, and/or the
?page=NURLs listed in your XML sitemapAn XML sitemap is a UTF-8 file listing the canonical URLs on your site (with optional lastmod) so search engines can discover and prioritize them. It's a discovery and diagnostic aid, not a guarantee of indexing — and Google ignores its priority and changefreq tags.. Whatever the renderer captures, the sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing.-and-links layer is your backstop.
If a live site is already exhibiting the merge bug and you need to stop the bleeding
before you can rebuild, my blunt emergency fix is to block the JavaScript file that
triggers infinite scroll in robots.txt so it physically can’t fire during
rendering — buying time to ship the proper paginated-URL architecture.
Navigation state: back, forward, refresh, and share have to reconstruct the same view
The History API point above covers half the contract — updating the address bar as a chunk becomes primary. The other half is making sure every entry path back into that URL actually reconstructs the right content, not just the right scroll position:
- Use
pushState()when a chunk becomes the primary visible content for the first time — that’s a real navigation step, and it’s what makes the back button meaningful. - Use
replaceState()for corrections that shouldn’t create their own back-button stop, like syncing the URL after a fast scroll past several chunks at once. - Listen for
popstateand re-render (or re-fetch) the chunk that matches the URL in the event. The browser’s default back/forward behavior restores scroll position, not the dynamic list state your JavaScript built — if a user hits back after your loader appended 40 more items, you need to reconstruct which items belong on that page, not just scroll them there. - Don’t lean on automatic scroll restoration alone to solve this. It controls where the viewport lands, not what content is present — if the underlying list can change between visits (new products added, items out of stock), scroll position without content reconstruction can strand the user in the wrong context.
This is the same discipline the paginated-URL fix already depends on: a chunk’s URL has to return the content it promised on a fresh load, a refresh, and a Search-Console live test — not just the first time it’s fetched mid-scroll.
Loading, error, and end-of-results states
A production implementation needs more states than “loading” and “loaded”:
- Initial load — the first chunk should already be in the raw HTML the server sends, not assembled entirely by JS after the fact.
- Next-chunk loading — a visible in-progress indicator so users (and anyone testing with assistive tech) know a fetch is underway.
- Empty — a distinct state for zero results, not a blank space that looks broken.
- Error / retry — a failed fetch shouldn’t silently strand the page with no way to try again, and a retry shouldn’t duplicate or reorder items already on the page.
- End of results — a clear signal, not an infinite spinner, once there’s nothing left to load.
None of this is Google-specific, but it’s the same reliability the paginated-URL fix depends on: if the loader can silently break mid-fetch, you can’t trust that any given crawl or user session actually captured the chunk it should have.
Accessibility and performance: two things infinite scroll doesn’t give you for free
Infinite scroll has no inherent Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. outcome, good or bad — it’s determined entirely by how you build it. Every appended chunk grows the DOM, and a large enough DOM raises layout and style-recalculation cost, so watch append cost, image loading, layout shift from content without reserved space, and long tasksAny main-thread task over 50 ms — the primary cause of INP regressions. as the list grows. On very long pages, consider virtualizing chunks that have scrolled far out of view (removing their DOM nodes) instead of letting the DOM grow unbounded.
Accessibility needs its own deliberate design, not an assumption that “it renders, so it’s fine”:
- Keyboard users need to be able to reach new content — and the footer or end-of-page navigation — without the page silently growing out from under their tab order.
- Screen reader users need new content announced without interrupting what they’re doing — a polite status region, not a disruptive alert, is the usual pattern.
- The WAI-ARIA feed design pattern is built for exactly this case: article-level regions inside a feed container, with defined keyboard behavior for moving between items and for reaching content before and after the feed.
- Focus shouldn’t silently jump or get lost when a new chunk loads.
None of this is optional cleanup. It’s the difference between infinite scroll that works for everyone and one that only works for a mouse user with JavaScript who never strays from the happy path.
The historical context: rel=next/prev is legacy
If you learned paginationPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does. years ago, you learned rel="next" / rel="prev". Google
introduced them in 2011 and paired them with its original 2014 “infinite scroll
search-friendly recommendations” (paginate the content, provide component pages).
Then in 2019 Google announced it hadn’t been using those tags for years and formally
dropped them. The pagination doc confirms it today: “In the past, Google used
<link rel="next" href="..."> and <link rel="prev" href="..."> to identify next page
and previous page relationships. Google no longer uses these tags, although these links
may still be used by other search engines.”
So the current Google recipe is unique URLs + crawlable links + the History API — no
rel=next/rel=prev required. But “other search engines” includes Bing, which
still respects them, so there’s no harm in keeping them in your markup for cross-engine
benefit and accessibility. Bing itself doesn’t publish infinite-scroll-specific
guidance; its stance reduces to the general JS-rendering caution its team laid out —
bingbotBingbot is Microsoft Bing's primary web crawler — the bot that discovers, fetches, and renders pages to build the Bing index. That index also powers Yahoo, DuckDuckGo, Ecosia, and Microsoft Copilot, so Bingbot's reach is far wider than Bing's own search-market share. can render JavaScript but “it is difficult for bingbot to process JavaScript at
scale,” so a crawlable paginated fallback helps Bing for exactly the same reason it
helps Google.
Ecommerce category pages: the highest-stakes case
The most common real-world infinite scroll is on ecommerce category / product listing pages (PLPs), and it’s where the risk costs actual money. If deep-catalog products past the first screenful never get indexed, they can’t rank, and you lose the long tail of product-level organic trafficVisitors from unpaid search results — it compounds without ad spend.. This is the same territory covered in depth in the category-page material — infinite scroll is one more reason those pages need a crawlable structure underneath the UX.
Two backstops matter here:
- XML sitemaps listing every canonical product and paginated category URL, so discovery doesn’t depend on the renderer.
- A Merchant Center product feed, which feeds Google product data independently of whatever the category page’s renderer captures.
Lumar’s analysis of top UK fashion retailers found infinite scroll to be, in their words, “the biggest loser when it comes to indexability and SEO friendliness” among the pagination patterns — a useful reminder that this isn’t a theoretical edge case, it’s the default failure mode of a very popular PLP UX. (Lumar’s specific percentage figures should be read from their live report before citing an exact number.)
Infinite scroll vs. pagination vs. load more
Google’s pagination doc frames three UX patterns and is honest about the tradeoffs. Infinite scroll “uses a single page for all content” and is “intuitive — the user just keeps scrolling,” but it “can lead to ‘scrolling fatigue’ because of unclear result size” and “can’t handle very large numbers of results.” Classic numbered pagination is the most robust for SEO because every page is inherently a real URL. “Load more” sits in between — fine if the button is (or wraps) a real link to a paginated URL, useless for SEO if it’s a pure click handler.
The decision isn’t “which is allowed” — all three are allowed. It’s “which UX do you want, and did you build the crawlable URL layer underneath it.” Mueller’s 2023 summary is the whole thing in one line: “if each piece or virtual page is also accessible and findable through a unique URL, generally it should be fine to have infinite scroll.”
AI summary
A condensed take on the Advanced version:
- Root constraint: GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. doesn’t scroll or click. Content gated behind a scroll or click event is invisible to it by default (“Google Search does not interact with your page”).
- Google’s workaround: it renders in a very tall viewport (~411×12,140px mobile, ~1024×9,307px desktop) instead of scrolling.
- The failure mode: that tall viewport can trigger the scroll loader during renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., folding the next logical page into the current one — so two pages get indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. as a single URL. A “not indexed” page may actually be indexed as part of another URL.
- No guarantee: per Mueller, Google might load “two or three of these pages … but not everything.” Infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. alone is not a reliable deep-indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. method.
- The fix (architectural): persistent, unique, absolute per-chunk URLs (e.g.
?page=12), linked with crawlable<a href>, with the History API (pushState/replaceState) updating the address bar as each chunk becomes primary. - Trigger mechanism:
IntersectionObserver/ native lazy-load, not a rawscrolllistener. - Legacy note:
rel=next/rel=prevdropped by Google in 2019; Bing still supports it, so keep it for cross-engine benefit. - Ecommerce: PLPs are the highest-stakes case; back them with sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. and a Merchant CenterGoogle Merchant Center (GMC) is a free platform where retailers upload and manage product data so their products can appear across Google — Shopping, organic Search product grids, Images, Lens, and AI surfaces. Since 2020 it powers free (organic) product listings, not just paid Shopping ads. feed. Verify in the URL Inspection ToolA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version.’s rendered HTML.
- Emergency fix on a live merge bug: block the infinite-scroll JS file so it can’t fire during renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. while you rebuild.
- Navigation state:
pushStatefor a real navigation step,replaceStatefor in-place corrections, and apopstatehandler that reconstructs the chunk’s content — not just its scroll position — on back/forward. - Loading/error/end states: distinct initial-load, next-chunk-loading, empty, error/retry, and end-of-results states; a broken loader is a reliability problem before it’s an SEO one.
- AccessibilityWeb accessibility means designing sites so people with disabilities can use them, per the W3C's WCAG guidelines. It overlaps with SEO in specific, checkable ways — alt text, heading structure, descriptive link text, captions, and page speed all serve both audiences — but Google has said accessibility itself is not a ranking factor, and most WCAG success criteria (keyboard focus order, ARIA live regions, form labels) have no SEO effect at all. and performance: infinite scroll has no inherent Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. outcome (it’s what you build); keyboard reachability, non-disruptive announcements, and the WAI-ARIA feed pattern are separate design work from the indexing fix.
- Dated observations: treat the exact viewport pixel dimensions and the merge-bug mechanics as implementation-specific, not a stable spec — verify per URL.
Official documentation
Primary-source documentation on infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page., paginationPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does., and JS renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM..
- Fix lazy-loaded content — includes the “Support paginated loading for infinite scroll” section (unique per-chunk URLs, absolute page numbers, History API) and the URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. testing step. Last updated 2025-12-10.
- Pagination, incremental page loading, and their impact on Google Search — the three UX patterns (paginationPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does. / load more / infinite scroll), their pros/cons, the crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index.-interaction note, and the
rel=next/rel=prevdeprecation. - Infinite scroll search-friendly recommendations — the original 2014 blog post (historical; the
rel=next/rel=prevpairing it described is now superseded). - September 2023 SEO Office Hours Transcript — Mueller’s on-the-record restatement of the unique-URL rule.
- Understand the JavaScript SEO basics — the broader renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. context infinite scroll sits inside.
Bing / Microsoft
- bingbot Series: JavaScript, Dynamic Rendering, and Cloaking. Oh My! — Bing’s general JS-rendering guidance (no infinite-scroll-specific page exists; Bing still respects
rel=next/rel=prev).
Quotes from the source
On-the-record statements from Google and Bing. Each link is a deep link that jumps to the quoted passage on the source page.
Google — infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. & the paginated-loading rule
- “To implement infinite scroll in an indexable way, make sure your website supports paginated loading of these chunks.” … “Give each chunk its own persistent, unique URL.” — Google Search Central, “Fix lazy-loaded content.” Jump to quote
- “When a new page chunk is loaded in response to the user scrolling, and it becomes the primary visible element for the user, update the displayed URL using the History API.” Jump to quote
- “The methods mentioned don’t rely on user actions, such as scrolling or clicking, to load content, which is important as Google Search does not interact with your page.” Jump to quote
- “You can use the URL Inspection ToolA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. in Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. to see if all content was loaded. Check the rendered HTML to make sure your content is in the rendered HTML by looking for it in URL Inspection ToolA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version..” Jump to quote
Google — paginationPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does. doc: crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. behavior & rel=next/prev
- “Google’s crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. don’t ‘click’ buttons and generally don’t trigger JavaScript functions that require user actions to update the current page contents.” Jump to quote
- “In the past, Google used
<link rel="next" href="...">and<link rel="prev" href="...">to identify next page and previous page relationships. Google no longer uses these tags, although these links may still be used by other search engines.” Jump to quote
John Mueller, Google — September 2023 office hours
- “It depends how you implement infinite scrolling. if each piece or virtual page is also accessible and findable through a unique URL, generally it should be fine to have infinite scroll.” Jump to quote
John Mueller, Google — the “9000px viewport” tweet (Nov 2017)
- “GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. renders with a very tall viewport, which skews some CSS (often images). Try in Chrome dev-tools, eg 9000px high viewport.” — reproduced by Search Engine Roundtable. Read the coverage
Bing — general JS renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. (no infinite-scroll-specific page)
- “As we shared last week at SMX East, bingbotBingbot is Microsoft Bing's primary web crawler — the bot that discovers, fetches, and renders pages to build the Bing index. That index also powers Yahoo, DuckDuckGo, Ecosia, and Microsoft Copilot, so Bingbot's reach is far wider than Bing's own search-market share. is generally able to render JavaScriptMaking sure search engines can crawl, render, and index content that depends on JavaScript.. However, bingbotBingbot is Microsoft Bing's primary web crawler — the bot that discovers, fetches, and renders pages to build the Bing index. That index also powers Yahoo, DuckDuckGo, Ecosia, and Microsoft Copilot, so Bingbot's reach is far wider than Bing's own search-market share. does not necessarily support all the same JavaScript frameworksJavaScript frameworks — React, Vue, Angular, Next.js, Nuxt, Svelte, Astro — are libraries or meta-frameworks for building web UIs. Their SEO impact depends on rendering mode: SSR and SSG deliver pre-rendered HTML; CSR-only apps require Googlebot to execute JavaScript before it can index content. that are supported in the latest version of your favorite modern browser.” — Fabrice Canel & Frédéric Dubut, Microsoft Bing. Jump to quote
Which pagination pattern should you use?
Work top to bottom.
1. Does the content past the first screen need to rank in search?
- No (e.g. an internal-only feed, a logged-in dashboard) → any pattern is fine; optimize purely for UX.
- Yes → keep going.
2. Do you already have (or can you build) a real per-chunk URL for every batch?
- No, and you can’t → use classic numbered paginationPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does.. Every page is a real URL by default, so it’s the lowest-risk pattern for SEO.
- Yes → infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. or “load more” are both fine, continue.
3. How large is the set?
- Very large (thousands of items, deep catalog) → prefer numbered paginationPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does. or infinite-scroll-over-real-URLs; pure infinite scroll “can’t handle very large numbers of results.” Add sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. as a discovery backstop.
- Moderate → infinite scroll or load more, backed by paginated URLs, is fine.
4. Building infinite scroll — is it wired to real URLs + History API?
- No (scroll event only, no URLs) → do not ship. This is the setup that gets deep content merged/unindexed.
- Yes (
?page=NURLs + crawlable anchors +pushState) → ship it, then verify in the URL Inspection ToolA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version.’s rendered HTML.
5. Already live and a deep page “isn’t indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed.”?
- Check the URL Inspection ToolA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version.’s rendered HTML of the previous page/post first — the “missing” content may be merged there.
- If it is → emergency fix: block the infinite-scroll JS file so it can’t fire during renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., then rebuild on paginated URLs.
Search-friendly infinite scroll checklist
- Every content chunk has its own persistent, unique, absolute URL (e.g.
?page=2, not?date=yesterday). - Each URL returns the same content every time it loads (stable, not session-dependent).
- Chunks are linked with real
<a href>links, discoverable without running JS. - The visible URL updates via the History API (
pushState/replaceState) as each chunk becomes the primary content. - The scroll loader uses
IntersectionObserver(or native lazy-loading), not a rawscrollevent listener. - Paginated URLs are listed in the XML sitemapAn XML sitemap is a UTF-8 file listing the canonical URLs on your site (with optional lastmod) so search engines can discover and prioritize them. It's a discovery and diagnostic aid, not a guarantee of indexing — and Google ignores its priority and changefreq tags. (and, for ecommerce, backed by a Merchant CenterGoogle Merchant Center (GMC) is a free platform where retailers upload and manage product data so their products can appear across Google — Shopping, organic Search product grids, Images, Lens, and AI surfaces. Since 2020 it powers free (organic) product listings, not just paid Shopping ads. feed).
-
rel=next/rel=prevoptionally present for Bing (harmless for Google, which ignores it). - URL Inspection ToolA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. → rendered HTML confirms deep content is present and not merged from an adjacent page.
- Locally reproduced with a tall DevTools viewport (~9000px) to confirm the loader doesn’t over-fire during render.
- A
popstatehandler reconstructs chunk content on back/forward, not just scroll position. - Distinct loading, error/retry, empty, and end-of-results states exist — a failed fetch doesn’t silently strand the page.
- Keyboard users can reach new content and the page footer; new content is announced via a polite status region, not a disruptive alert.
What breaks infinite scroll for SEO
Scroll-event-only loading with no real URLs. The classic mistake. Content lives only in the DOM after a scroll fires — GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. never scrolls, so it’s invisible. There’s nothing to crawl and nothing to fall back on.
A “Load more” button that’s a pure click handler.
Feels safer than auto-scroll, isn’t. Google doesn’t click buttons either. It only helps
if the button is (or wraps) a real <a href> to a paginated URL.
Fragment/hash URLs for paginationPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does. (#page=2).
Fragments don’t create distinct crawlable URLs. Use real query-parameter or path-based
URLs instead.
Relative or unstable URLs (?date=yesterday, session-scoped content).
If the same URL returns different content on different loads, it can’t serve as a stable,
indexable page. Use absolute page numbers.
Ignoring the tall-viewport merge bug. Assuming “not indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed.” means Google is ignoring the page. In infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. it often means the content got folded into an adjacent URL by the render-time trigger — a different problem needing a different fix.
Blocking your JS/CSS globally as a “fix.” Blocking the specific infinite-scroll trigger file is a deliberate emergency measure. Blocking all JS/CSS is not — it wrecks renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. across the whole page.
Infinite scroll SEO — cheat sheet
The three UX patterns
| Pattern | Inherently crawlable? | SEO risk | Best for |
|---|---|---|---|
| Numbered paginationPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does. | Yes (real URLs) | Lowest | Large sets, deep catalogs |
| Load more (button) | Only if button = real link | Medium | Moderate sets |
| Infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. | No — needs URL layer added | Highest without URLs | Feeds, browsing UX |
The non-negotiables for infinite scroll
- Persistent, unique, absolute URL per chunk (
?page=12). - Same content on every load (no
?date=yesterday). - Crawlable
<a href>links between chunks. - History API (
pushState/replaceState) to sync the address bar. IntersectionObserver, not a rawscrolllistener.
Fast facts
- GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer.: doesn’t scroll, doesn’t click.
- Render viewport (reported): ~411×12,140px mobile, ~1024×9,307px desktop.
- Merge bug: tall viewport can fire the loader mid-render → two pages indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. as one.
rel=next/rel=prev: Google dropped it in 2019; Bing still uses it.- Verify: URL Inspection ToolA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. → rendered HTML.
- Emergency fix on a live merge bug: block the infinite-scroll JS file.
What good and bad implementations look like
Bad — scroll-only, invisible to Google
The category page ships 24 products in the HTML. A scroll listener fetches the next
24 and appends them. There are no ?page=N URLs anywhere, no anchors, no History API.
GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. loads the page, never scrolls, and indexes 24 products. The other 300 in the
catalog are undiscoverable through this page.
Bad — the merge bug in the wild
A publisher’s blog uses infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. to append the next post below the current one. A writer complains their new article “won’t indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed..” It’s actually indexed — as part of the previous post’s URL, because Google’s tall render viewport triggered the loader and folded the next article into the current page’s render. Fix: paginate properly, and in the meantime block the infinite-scroll trigger script.
Good — infinite scroll over real URLs
The same category exists at /shoes?page=1, /shoes?page=2, … each a real URL returning
stable content, all listed in the XML sitemapAn XML sitemap is a UTF-8 file listing the canonical URLs on your site (with optional lastmod) so search engines can discover and prioritize them. It's a discovery and diagnostic aid, not a guarantee of indexing — and Google ignores its priority and changefreq tags. and linked with <a href> at the foot of the
listing. For humans, IntersectionObserver loads the next chunk as they approach the bottom
and history.pushState() updates the address bar to ?page=2 when that batch becomes the
primary content. Google reaches every page directly via the links and sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing.; the scroll UX
is pure enhancement on top.
Implementation and diagnostic snippets
The History API pattern (client-side)
Load each chunk when it’s about to enter view with IntersectionObserver, then swap the
visible URL when that chunk becomes primary. The key is that the ?page=N URLs are real
pages that exist server-side regardless of this script.
// A sentinel element sits at the bottom of the current chunk.
const sentinel = document.querySelector('#load-more-sentinel');
let nextPage = 2;
const io = new IntersectionObserver(async (entries) => {
if (!entries[0].isIntersecting) return;
const res = await fetch(`/shoes?page=${nextPage}&partial=1`);
const html = await res.text();
document.querySelector('#product-grid').insertAdjacentHTML('beforeend', html);
// Update the address bar so refresh/share/link land on this chunk.
// pushState adds a history entry; replaceState if you don't want back-button steps.
history.pushState({ page: nextPage }, '', `/shoes?page=${nextPage}`);
nextPage++;
}, { rootMargin: '600px' }); // start loading before the user hits the very bottom
io.observe(sentinel);And crucially, the crawlable fallback still lives in the DOM — this is what Google follows:
<nav aria-label="Pagination">
<a href="/shoes?page=2" rel="next">Next</a>
<!-- rel="next"/"prev" is ignored by Google since 2019 but still used by Bing -->
</nav>DevTools console: does your loader fire without a real scroll?
Simulate Google’s tall viewport locally, then check whether extra chunks loaded on their own. In Chrome DevTools, set a very tall custom device viewport (~1024×9000), reload, and run this in the Console to count how many chunks are present with no manual scrolling:
// Count rendered product cards (adjust the selector to your markup)
console.log('cards rendered without scrolling:', document.querySelectorAll('#product-grid .product-card').length);
// If this is much higher than your per-page count, the loader is over-firing on height alone.DevTools console: confirm the paginated URLs actually exist
Before trusting the fallback, verify each ?page=N returns real, distinct content
server-side (not a JS-only route):
// Run in the console; a real paginated URL should return HTML containing products.
for (const n of [2, 3, 4]) {
const html = await (await fetch(`/shoes?page=${n}`)).text();
console.log(`page ${n}: ${html.includes('product-card') ? 'has products ✅' : 'EMPTY — JS-only? ❌'}`);
}Bookmarklet: jump straight to a page’s rendered-HTML check
Drag this to your bookmarks bar to open the current URL in Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results.’s URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. Tool, where you then read the rendered HTML (not the source) to see how far down Google captured content:
javascript:(()=>{const u=encodeURIComponent(location.href);open('https://search.google.com/search-console/inspect?resource_id=&id='+u,'_blank');})();You’ll still pick your verified property inside Search ConsoleGoogle's free tool for monitoring crawling, indexing, and search performance.; the bookmarklet just
saves the copy-paste of the current URL. Prove infinite scroll is indexable after launch
Test every chunk as a standalone URL
Test to run: Request the first, middle, and last paginated URLs directly with JavaScript disabled. Expected result: Each returns stable, unique content and a successful response without requiring a scroll. Failure interpretation: The URL layer is cosmetic or still depends on client interaction. Monitoring window: Immediate after deployment. Rollback trigger: Any listed chunk redirectsA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. to the first page, returns the shared shell, or changes content between requests.
Test crawler discovery without interaction
Test to run: Inspect the rendered DOM before scrolling and extract the paginationPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does.
links. Expected result: Sequential chunks are linked through real absolute or
root-relative href values. Failure interpretation: The crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. has no path beyond
the first loaded set. Monitoring window: Immediate. Rollback trigger: The next
chunk exists only behind a button handler or scroll event.
Test for the tall-viewport merge bug
Test to run: Render the first chunk in a very tall Chrome viewport, then search the DOM for a distinctive item from the next chunk. Expected result: The first URL does not absorb the next URL’s primary content. Failure interpretation: The loader fires during renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. even without user interaction. Monitoring window: Immediate locally, then recheck URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. after Google recrawlsCrawl frequency is how often a search engine comes back to re-fetch a page it already knows about. Popular pages that change often get refreshed many times a day; stable pages can go weeks or months between crawls — and you influence it indirectly, not by setting a dial.. Rollback trigger: Two logical chunks appear as one document or the address bar does not track the primary visible chunk.
Test yourself: Infinite Scroll SEO
Five quick questions on making infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. indexable. Pick an answer for each, then check.
Resources worth your time
My related writing
- JavaScript SEO Issues & Best Practices — my full write-up, including the “Infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. issues” section (two pages indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. as one) and the “What GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. sees” viewport figures.
- The Beginner’s Guide to Technical SEO — where renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. and crawlabilityCrawlability is how well search engine crawlers can discover, access, and fetch a site's pages. A crawlability issue is any technical condition — blocked access, broken links, server failures, or bloated URL inventory — that stops pages from reaching the index. fit in the bigger picture.
My speaking
- How Search Works (SlideShare) — my walkthrough of crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor., renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed., and ranking, which is the backdrop to every infinite-scroll decision. (My standing disclaimer applies: “This is my understanding of systems… not going to be 100% complete or accurate.”)
From around the industry
- Google Search Central, Fix lazy-loaded content — the current, authoritative “Support paginated loading for infinite scroll” guidance.
- Google Search Central, Pagination, incremental page loading, and their impact on Google Search — the three UX patterns and the
rel=next/rel=prevdeprecation. - Matt G. Southern, How Google Crawls Pages With Infinite Scrolling (Search Engine Journal) — the Mueller “two or three pages loaded on one page” explanation of the merge risk.
- Matt G. Southern, Google’s Martin Splitt Explains Why Infinite Scroll Causes SEO Problems (Search Engine Journal) — “GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. doesn’t scroll,” IntersectionObserver vs. scroll, and “test your implementations.”
- Barry Schwartz, GoogleBot Crawls & Renders Tall, With 9000px High Viewport? (Search Engine Roundtable) — the origin of the tall-viewport explanation.
- Matthew Edgar, SEO Friendly Infinite Scroll — the “component pages” framing (chunks that work independently, even with JS off).
- Go Fish Digital, How To Implement Infinite Scroll For SEO — an implementation-oriented walkthrough.
- Lumar, State of Pagination in eCommerce — the top-UK-fashion-retailer indexability analysis that rated infinite scroll the worst-performing pattern.
Infinite Scroll
Infinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page.
Related: JavaScript SEO, Pagination, Lazy Loading
Infinite Scroll
Infinite scroll is a UX pattern where a page automatically loads more content — more products, more articles, more results — as the user scrolls toward the bottom, instead of requiring a click to a new numbered page. It’s one of the three paginationPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does. UX patterns Google recognizes, alongside classic numbered paginationPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does. and a “load more” button.
For SEO, the defining fact is that GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. doesn’t scroll and doesn’t click. It never fires the scroll event (or the button click) that triggers the JavaScript loader, so any content that only appears after a user action is invisible to it by default. Google’s workaround is to render pages in an unusually tall viewport (reported at roughly 411×12,140px on “mobile” and 1024×9,307px on “desktop”) so that content a few screens down is already inside the rendered viewport without anyone scrolling — but that same tall viewport can trigger the scroll loader during renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., pulling the next logical page’s content into the current page’s render, so two distinct pages get flattened and indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. as one.
The fix is architectural, not a patch: build infinite scroll on top of real, paginated, per-chunk URLs (for example ?page=2), linked with crawlable <a href> links, and update the visible URL with the History API (pushState/replaceState) as the user scrolls past each chunk boundary. That gives search engines a crawlable fallback no matter what the renderer captures. Google has no policy against infinite scroll as a pattern — the risk is purely crawlabilityCrawlability is how well search engine crawlers can discover, access, and fetch a site's pages. A crawlability issue is any technical condition — blocked access, broken links, server failures, or bloated URL inventory — that stops pages from reaching the index. and indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. when it’s built without that paginated-URL backstop.
Related: JavaScript SEO, Pagination, Lazy Loading
Build-time retrieval analysis plus live signals for this exact article. The automatic chunk report includes a deterministic readiness score and is ready without a model download.
Search Console
sampleGA4 traffic (28d)
sampleCloudflare traffic (7d)
sampledCrUX field data (28d, phone)
sampleGoogle NLP entities
localChangelog
Updated Jul 18, 2026.
Editorial summary and recorded change details.Summary
Added the production-hardening gaps the research review flagged: a real back/forward navigation-state contract, distinct loading/error/end-of-results states, accessibility and Core Web Vitals guidance, and clearer dated-observation framing around the tall-viewport figures.
Change details
-
Added a 'Navigation state' section covering pushState vs. replaceState, popstate reconstruction, and why automatic scroll restoration alone doesn't solve the wrong-content-on-back-button problem.
-
Added a 'Loading, error, and end-of-results states' section (initial load, next-chunk loading, empty, error/retry, end of results).
-
Added an 'Accessibility and performance' section: infinite scroll has no inherent Core Web Vitals outcome, plus keyboard/focus/WAI-ARIA feed-pattern guidance.
-
Reframed the tall-viewport pixel dimensions and merge-bug mechanics as dated, implementation-specific observations to verify per URL, not a stable platform spec.
Full comparison unavailable — no prior snapshot was archived for this revision.