Guide Infinite Scroll SEO

How to implement infinite scroll sans losing votre indexation — pourquoi Googlebot doesn't scroll, the tall-viewport render trick que flattens two pages into un, the paginated-URL + History API fix, and the ecommerce category-page cas.

Première publication : 3 juil. 2026 · Dernière mise à jour : 3 août 2026 · Advanced
Langues

Infinite scroll loads plus content as vous scroll, au lieu de via numbered pages — and Googlebot jamais scrolls or clicks, so anything gated behind que action is invisible by par défaut. Google renders in a very tall viewport (à propos de 411×12,140px mobile, 1024×9,307px desktop) as a workaround, but que même tall viewport peut trigger the scroll loader during rendering and fold two logical pages into un indexé URL — a échec mode où a 'non indexée' page is en réalité indexé as partie of un autre. The fix is architectural: give every chunk a réel, persistent, absolute URL (comme ?page=2), lien les with crawlable anchors, and mettre à jour the adresse bar with the History API as the utilisateur scrolls. rel=suivant/prev is legacy (Google dropped it in 2019; Bing encore supports it). On ecommerce category pages, back it tout with sitemaps or a Merchant Center feed and vérifier in the Inspection d’URL Tool's rendered HTML. A production construire aussi nécessite a réel popstate/back-forward contract, distinct chargement/error/fin states, and deliberate accessibility — none of que comes pour free simplement parce que the indexation fix is in placer.

TL;DR — Googlebot jamais scrolls and jamais clicks, so scroll-gated content is invisible by par défaut. Google’s workaround is to render in a very tall viewport (roughly 411×12,140px mobile, 1024×9,307px desktop) — but que même height peut trigger the scroll loader during rendering, folding the suivant logical page into the current un so two pages obtenir indexé as a unique URL. The durable fix is architectural: persistent, absolute, per-chunk URLs (e.g. ?page=12), lié with crawlable anchors, with the History API updating the adresse bar as chaque chunk becomes principal. rel=next/rel=prev is legacy pour Google (dropped 2019) but encore respected by Bing. On ecommerce PLPs, sitemaps or a Merchant Center feed are a discovery backstop. Vérifier everything in the Inspection d’URL Tool’s rendered HTML.

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 API

Premier, a disambiguation

Si vous search “Google infinite scroll” you’ll hit results à propos de Google’s propre continuous scroll on its résultats de recherche pages — a SERP fonctionnalité Google turned on and alors discontinued in mid-2024. That’s a Google-product UX decision and has nothing to do with how Googlebot crawls votre site. Ce article is à propos de the latter: infinite scroll as a chargement pattern on votre propre pages, and si Google peut index ce que it loads.

The core constraint: Google doesn’t interact with votre page

Everything ici follows from un fact. Google’s propre lazy-loading docs dire the recommended patterns “don’t rely on utilisateur actions, tel as scrolling or clicking, to charger content, qui is important as Recherche Google ne fait pas interact with votre page.” The pagination doc dit it même plus plainly: “Google’s robots d’exploration don’t ‘click’ buttons and généralement don’t trigger JavaScript functions que exiger utilisateur actions to mettre à jour the current page contents.”

As I put it in my propre JavaScript SEO guide: “Googlebot doesn’t prendre action on webpages. It’s pas going to click choses or scroll, but que doesn’t mean it doesn’t have workarounds. Tant que content is chargé in the DOM sans a nécessaire action, Google va voir it. Si it’s pas chargé into the DOM jusqu’à après a click, alors le contenu won’t be trouvé.”

So infinite scroll que seulement triggers on a réel scroll event is a content-discovery problem avant it’s anything sinon.

Google’s workaround: a very tall viewport

Google doesn’t simulate scrolling. À la place it renders votre page in an unusually tall viewport, so content a few screens bas is déjà à l’intérieur the rendered area sans anyone scrolling. The earliest on-record hint of ce was John Mueller’s 2017 remarque que “Googlebot renders with a very tall viewport, qui skews some CSS (souvent images). Essayer in Chrome dev-tools, eg 9000px élevé viewport.”

The spécifique numbers I’ve documented: pour mobile, Google loads lune 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. Pour desktop, it fait the même and goes from 1024×768 pixels to 1024×9307 pixels.” (I haven’t seen recent re-tests of ceux exact figures, and ils 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 que Google fakes “seeing far bas the page” with height, pas with movement.

Treat les deux the exact pixel dimensions and the two-pages-merged behavior ci-dessous as dated, implementation-specific observations plutôt que a stable platform contract — Google doesn’t publish an official spec pour soit number, and rendering behavior peut modifier. Don’t assume votre site behaves the même façon; confirmer current behavior pour votre propre URLs with the rendered-HTML tester in the suivant section au lieu de taking ces figures as a guarantee.

The échec mode nobody explique: two pages indexé as un

A height-triggered loader can fire during rendering and merge two logical pages under one indexed URL. Source : /technical-seo/javascript-seo/

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 où the tall viewport bites back. Parce que the render viewport is so tall, the scroll-triggered loader peut fire during rendering même though nothing “scrolled” in the human sense — the sheer DOM height peut be suffisant to satisfy an IntersectionObserver or a scroll-position vérifier. Quand que se produit, the loader appends the suivant logical page’s content into the current page’s render, and Google indexes the merged result as a unique URL.

I’ve diagnosed ce several times. From my JavaScript SEO guide:

“Un autre problème I’ve seen with ce setup is, occasionally, two pages obtenir indexé as un. I’ve seen ce a few times quand personnes said ils couldn’t obtenir leur page indexé. But I’ve trouvé leur content indexé as partie of un autre page that’s usually the previous post from les.”

“My theory is que quand Google resized the viewport to be plus long, it triggered the infinite scroll and chargé un autre article in quand it was rendering. In ce cas, ce que I recommend is to block the JavaScript fichier que handles the infinite scrolling so the functionality can’t trigger.”

John Mueller décrit the même mechanic from Google’s side in a 2022 office-hours session: Google renders with a élevé viewport, que “voudrait trigger some amount of infinite scrolling,” and “we pourrait have two or three of ces pages chargé on un page with infinite scroll, but pas everything.” (Que office-hours quote is relayed via Moteur de recherche Journal’s write-up, pas confirmed contre the principal recording.)

Two consequences fall out of ce:

  1. There’s aucun guarantee of how beaucoup obtient pulled in. Pourrait be nothing supplémentaire, pourrait be two or three pages, jamais reliably everything. Infinite scroll alone n’est pas a dependable façon to obtenir deep content indexé.
  2. “Not indexed” peut be a misdiagnosis. The manquant page may pas be manquant at tout — it may be indexé as partie of an précédent URL. Que nécessite a différent fix que a normal indexation bug.

How to diagnose it

Utiliser Search Console’s Inspection d’URL Outil and lire the rendered HTML, pas the raw source. Google’s docs are explicit: “Vous pouvez utiliser the Inspection d’URL Outil in Search Console to voir si tout content was chargé. Vérifier the rendered HTML to assurez-vous votre content is in the rendered HTML by looking pour it in Inspection d’URL Outil.” Search the rendered HTML pour content vous expect to be on page 1 seulement. Si vous trouver content from page 2 (or the suivant article) sitting à l’intérieur page 1’s render, you’ve reproduced the merge bug.

Vous pouvez aussi replicate the tall viewport locally: ouvrir Chrome DevTools, définir a very tall custom viewport (Mueller’s suggestion was ~9000px), and charger lune page to voir si votre loader fires with aucun scrolling.

The fix: paginated URLs + the History API

The durable fix is architectural, straight from Google’s current lazy-loading doc. To faire infinite scroll indexable, “assurez-vous votre website supports paginated chargement of ces chunks”:

  • “Give each chunk its own persistent, unique URL.”
  • “Garantir que le contenu affiché on chaque URL remains the même every temps it’s chargé in a navigateur” — Google suggests absolute page numbers comme ?page=12.
  • “Avoid using relative elements like ?date=yesterday in these URLs” — an adresse que renvoie différent content chaque charger is unusable as a canonical.
  • “Lien sequentially to the individual URLs so que moteur de recherches peut découvrir the URLs in a paginated définir” — réel <a href> liens, pas click handlers.
  • “Quand a nouveau page chunk is chargé in réponse to the utilisateur scrolling, and it becomes the principal visible element pour the utilisateur, mettre à jour the affiché URL en utilisant the History API.”

Que dernier point is the elegant partie. history.pushState() / replaceState() swaps l’URL in the adresse bar as the utilisateur scrolls past chaque boundary — so the visible URL toujours matches the principal content, and the utilisateur peut refresh, share, and lien to exactly où ils are. Meanwhile the crawlable ?page=N URLs exist independently, so Google peut reach every chunk directement si or pas the renderer ever triggers the scroll.

Two implementation notes que matter:

  • Utiliser IntersectionObserver (or native navigateur lazy-loading), pas a raw scroll listener. It performs far meilleur (aucun scroll-thrash) and it’s the “charger quand visible” mechanism Google endorses pour deferred content.
  • Garder the paginated définir discoverable independently of the JS. Réel anchors in the DOM, and/or the ?page=N URLs listed in votre XML sitemap. Whatever the renderer captures, le sitemap-and-links couche is votre backstop.

Si a live site is déjà exhibiting the merge bug and vous devez arrêter the bleeding avant vous pouvez rebuild, my blunt emergency fix is to block the JavaScript fichier que triggers infinite scroll in robots.txt so it physically can’t fire during rendering — buying temps to ship the proper paginated-URL architecture.

The History API point ci-dessus covers half the contract — updating the adresse bar as a chunk becomes principal. The autre half is making certain every entry chemin back into que URL en réalité reconstructs the correct content, pas simplement the correct scroll position:

  • Utiliser pushState() quand a chunk becomes the principal visible content pour the premier temps — that’s a réel navigation step, and it’s ce que rend the back button meaningful.
  • Utiliser replaceState() pour corrections que shouldn’t créer leur propre back-button arrêter, comme syncing l’URL après a fast scroll past several chunks at une fois.
  • Listen pour popstate and re-render (or re-fetch) the chunk que matches l’URL in the event. Le navigateur’s par défaut back/forward behavior restores scroll position, pas the dynamic liste state votre JavaScript construit — si a utilisateur hits back après votre loader appended 40 plus items, vous devez reconstruct qui items belong on que page, pas simplement scroll les là.
  • Don’t lean on automatic scroll restoration alone to solve ce. It contrôle où the viewport lands, pas ce que content is présent — si the underlying liste peut modifier entre visits (nouveau products ajouté, items out of stock), scroll position sans content reconstruction peut strand the utilisateur in the incorrect context.

Ce is the même discipline the paginated-URL fix déjà dépend on: a chunk’s URL has to retourner le contenu it promised on a fresh charger, a refresh, and a Search-Console live tester — pas simplement the premier temps it’s récupéré mid-scroll.

Chargement, error, and end-of-results states

A production implementation nécessite plus states que “loading” and “loaded”:

  • Initial charger — the premier chunk devrait déjà be in the raw HTML le serveur sends, pas assembled entirely by JS après the fact.
  • Next-chunk chargement — a visible in-progress indicator so utilisateurs (and anyone testing with assistive tech) know a récupérer is underway.
  • Vide — a distinct state pour zero results, pas a blank space que semble broken.
  • Error / retry — a failed récupérer shouldn’t silently strand lune page with aucun façon to essayer à nouveau, and a retry shouldn’t duplicate or reorder items déjà on lune page.
  • Fin of results — a clair signal, pas an infinite spinner, une fois there’s nothing left to charger.

None of ce is Google-specific, but it’s the même reliability the paginated-URL fix dépend on: si the loader peut silently break mid-fetch, vous pouvez’t trust que quelconque donné explorer or utilisateur session en réalité captured the chunk it devrait have.

Accessibility and performances: two choses infinite scroll doesn’t give vous pour free

Infinite scroll has aucun inherent Core Web Vitals outcome, bon or bad — it’s determined entirely by how vous construire it. Every appended chunk grows the DOM, and a grand suffisant DOM raises layout and style-recalculation cost, so watch append cost, image chargement, layout shift from content sans reserved space, and long tasks as the liste grows. On very long pages, considérer virtualizing chunks que have scrolled far out of view (removing leur DOM nodes) au lieu de letting the DOM grow unbounded.

Accessibility nécessite its propre deliberate design, pas an assumption que “it renders, so it’s fine”:

  • Keyboard utilisateurs besoin to be able to reach nouveau content — and the footer or end-of-page navigation — sans lune page silently growing out from sous leur tab order.
  • Screen reader utilisateurs besoin nouveau content announced sans interrupting ce que they’re doing — a polite status region, pas a disruptive alert, is the usual pattern.
  • The WAI-ARIA feed design pattern is construit pour exactly ce cas: article-level regions à l’intérieur a feed container, with défini keyboard behavior pour moving entre items and pour reaching content avant and après the feed.
  • Focus shouldn’t silently jump or obtenir lost quand a nouveau chunk loads.

None of ce is optional cleanup. It’s the difference entre infinite scroll que fonctionne pour everyone and un que seulement fonctionne pour a mouse utilisateur with JavaScript who jamais strays from the happy chemin.

The historical context: rel=suivant/prev is legacy

Si vous learned pagination années ago, vous learned rel="next" / rel="prev". Google introduced les in 2011 and paired les with its original 2014 “infinite scroll search-friendly recommendations” (paginate le contenu, provide component pages). Alors in 2019 Google announced it hadn’t been en utilisant ceux tags pour années and formally dropped les. The pagination doc confirms it today: “In the past, Google utilisé <link rel="next" href="..."> and <link rel="prev" href="..."> to identifier suivant page and previous page relationships. Google ne … plus uses ces tags, although ces liens may encore be utilisé by autre moteur de recherches.”

So the current Google recipe is unique URLs + crawlable liens + the History API — aucun rel=next/rel=prev requis. But “other search engines” inclut Bing, qui encore respects les, so there’s aucun harm in keeping les in votre markup pour 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 — bingbot peut render JavaScript but “it is difficult pour bingbot to traiter JavaScript at scale,” so a crawlable paginated fallback helps Bing pour exactly the même raison it helps Google.

Ecommerce category pages: the highest-stakes cas

The la plupart courant real-world infinite scroll is on ecommerce category / product listing pages (PLPs), and it’s où the risk costs réel money. Si deep-catalog products past the premier screenful jamais obtenir indexé, ils can’t rank, and vous lose the long tail of product-level trafic organique. Ce is the même territory covered in depth in the category-page material — infinite scroll is un plus raison ceux pages besoin a crawlable structure underneath the UX.

Two backstops matter ici:

  • XML sitemaps listing every canonical product and paginated category URL, so discovery doesn’t depend on the renderer.
  • A Merchant Center product feed, qui feeds Google product données independently of whatever the category page’s renderer captures.

Lumar’s analysis of top UK fashion retailers trouvé infinite scroll to be, in leur words, “the biggest loser when it comes to indexability and SEO friendliness” among the pagination patterns — a utile reminder que ce isn’t a theoretical edge cas, it’s the par défaut échec mode of a very popular PLP UX. (Lumar’s spécifique percentage figures devrait be lire from leur live report avant citing an exact number.)

Infinite scroll vs. pagination vs. charger plus

Google’s pagination doc frames three UX patterns and is honest à propos de the tradeoffs. Infinite scroll “uses a single page for all content” and is “intuitive — the utilisateur simplement garde scrolling,” but it “peut lead to ‘scrolling fatigue’ parce que of unclear result size” and “can’t handle very grand numbers of results.” Classic numbered pagination is the la plupart robust pour le SEO parce que every page is inherently a réel URL. “Load more” sits in entre — fine si the button is (or wraps) a réel lien to a paginated URL, useless pour SEO si it’s a pure click handler.

The decision isn’t “which is allowed” — tout three are allowed. It’s “qui UX do vous vouloir, and did vous construire the crawlable URL couche underneath it.” Mueller’s 2023 summary is the whole chose in un line: “si chaque piece or virtual page is aussi accessible and findable via a unique URL, généralement it devrait be fine to have infinite scroll.”

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.