The Case for Infinite Scroll on Collection Pages
Traditional paginated collection pages force customers to click through numbered pages, breaking their browsing flow and adding friction to product discovery. Infinite scroll eliminates this by automatically loading the next batch of products as the user scrolls toward the bottom of the page. On mobile, where pagination buttons are particularly cumbersome, this pattern feels native and intuitive. The Intersection Observer API makes this implementation clean and performant: instead of listening to scroll events on every frame, you observe a sentinel element placed after the last product card and trigger a fetch only when that sentinel enters the viewport.
The implementation starts with rendering the first page of products server-side using Liquid, which ensures fast initial load and full SEO crawlability. You then place a hidden sentinel div below the product grid. Your JavaScript creates an IntersectionObserver that watches this sentinel with a root margin that triggers loading slightly before the user actually reaches the bottom, creating a seamless experience. When the observer fires, you fetch the next page of products, append them to the grid, and move the sentinel below the newly added products. This cycle repeats until there are no more pages to load.
Fetching with the Storefront API
For headless or hybrid implementations, the Storefront API's collection query supports cursor-based pagination through the products connection. You request the first N products along with the pageInfo object, which provides hasNextPage and endCursor fields. When the observer triggers, you send a new query using the endCursor as the "after" argument to fetch the next batch. This is more reliable than offset-based pagination because it handles products being added or removed between page loads without duplicating or skipping items.
In a Liquid-based theme, you can achieve the same result without the Storefront API by fetching the next page's HTML via a standard AJAX request to the collection URL with a page parameter, then extracting the product cards from the response and appending them to the current grid. This approach is simpler to implement and does not require a Storefront API access token, but it transfers more data per request since you are fetching a full HTML page and discarding everything except the product grid. For stores with large catalogs, the Storefront API approach is more efficient because you request only the data you need in a structured JSON format.
SEO and Fallback Considerations
The biggest concern with infinite scroll is SEO. Search engine crawlers may not execute JavaScript, meaning they will only see the products rendered on the initial server-side page load. To address this, always render the first page of products with Liquid and include rel="next" and rel="prev" link elements in the head that point to the traditional paginated URLs. This tells crawlers that additional content exists on subsequent pages. Additionally, update the browser's URL using the History API as the user scrolls through pages, so that if they share or bookmark a link, it reflects their approximate position in the collection.
Always provide a fallback for users with JavaScript disabled or on connections where the script fails to load. The simplest fallback is standard pagination links rendered by Liquid and hidden via CSS when JavaScript is active. If the script loads successfully, it hides the pagination and activates the infinite scroll behavior. If it does not, the user sees traditional page links and can still browse the full collection. This progressive enhancement approach ensures that no customer is locked out of your catalog regardless of their browser capabilities.
Performance optimization matters as the product grid grows. Appending hundreds of DOM nodes degrades scroll performance, especially on mobile devices. Consider implementing a virtual scrolling technique that removes off-screen product cards from the DOM and re-inserts them as the user scrolls back, or cap the infinite scroll at a reasonable limit (e.g., 100 products) and show a "Load More" button for the remainder. This balances the seamless browsing experience with the practical limits of browser rendering.