Estafette
Compose Login
You are browsing eu.zone1 in read-only mode. Log in to participate.
rss-bridge 2025-10-29T17:14:09+00:00

Improving performance by prefetching product pages from Etsy Search

Rarely are there opportunities for big, bold, game-changing improvements in web performance. The Speculation Rules API (SRA) is a recent browser development that offers just such an opportunity. This post details a joint effort between the search and the web performance teams at Etsy to implement SRA on Etsy search pages and drastically improve the performance of product listing pages with some metrics seeing 20-24% improvements and some dropping all the way to 0ms values.
Prefetching Options
There are two main ways to predictively fetch resources for the next page:

allows us to instruct the browser to download a resource we believe we'll need soon. The resource can be anything, like a static asset or an HTML page.
Speculation Rules API (SRA) is a recently updated browser API which allows for a JSON definition to dictate what page A wants to do with page B. The "do"-ing can be either prefetching (just download the HTML) or prerendering (load the page, including its static assets, and render it completely). The prerendering happens in a new browser process and page B is ready to be swapped with the current page A instantaneously when the user navigates to B.

While implementing full prerendering is likely to yield more impressive performance improvements, it is a bigger and riskier investment, mostly related to the side effects of executing the JavaScript on the target page B. Starting with prefetching is a good first step into exploring SRA.
The benefits of using SRA over link prefetch will become evident further in the article but the topline highlights include: a simpler API to define what is prefetched (via a CSS selector rather than do-it-yourself bespoke JavaScript), convenient utilities to define when, as well as where (memory and HTTP cache) prefetching happens, and a built-in upgrade path to full on prerendering.
Implementing Speculation Rules
The Search team at Etsy recently ran an A/B experiment to use the Speculation Rules API to prefetch the listing page when hovering over organic listing cards on the desktop search page on Chromium browsers. To do this, we added a new tag to the search page with JSON that defines how we want the prefetching to work, like so:

{
"prefetch": [{
"where": {
"and": [
{
"href_matches": "/{/}?listing/"
},
{
"selector_matches": "[data-sr-prefetch='1']"
}
]
},
"eagerness": "moderate"
}]
}

This instructs the browser to download the HTML for a listing page when:

the user hovers over a link to a listing page for 200 milliseconds (defined by the “moderate” eagerness property), and
the link has a data-sr-prefetch attribute

The data attribute allows us to more precisely opt in pages that are eligible for prefetching.
Lessons learned
In terms of changes to the page’s code, the implementation of SRA was straightforward. As such, we spent most of our time testing that everything was working as expected and that our systems and analytics were not inadvertently affected. And we found some surprises along the way, related to all the little details modern web pages use (such as cookies, redirects, new tabs).
Allow us to share a few lessons in prefetching...
Two ways to prefetch
As mentioned earlier, prefetching can happen one of two ways: or speculative prefetch (the one using SRA). So what sets them apart?
They do work mostly the same, except that the speculative prefetch caches the page in both memory and the HTTP cache. The only uses the HTTP cache and merely downloads the specified resource.
This makes the SRA way of prefetching more advantageous than the prefetch because of the memory cache.
Two speculative prefetches only
We also discovered the number of prefetched pages that are kept in memory is restricted to two. When you prefetch a third page, the first one is evicted from the memory cache. The HTTP cache still works as usual. So again, the SRA prefetching is preferable to the prefetch due to the difference in caching we just described.
It’s helpful while debugging to be aware of the eviction of the prefetched page from memory. But rest assured, the downloaded page is still cached locally.
Eagerness
While advises the browser to load a resource as soon as it sees the in the DOM, the speculative prefetch is more nuanced, offering eager, immediate, conservative and moderate loading. We selected moderate eagerness, which prefetches after the user has hovered over a link for 200ms.
Exploring our options we found that the immediate eagerness would trigger a significantly larger number of prefetches (since it executes immediately and prefetches all eligible pages), and we wanted to avoid creating new server requests for listing cards with a low likelihood of being clicked. However, the immediate eagerness setting could be worth considering if the cost of additional requests is very low. The conservative eagerness executes on pointer or touch down, providing a very small head start over normal browser behavior and therefore greatly reducing the potential benefits of prefetching. Conservative eagerness may only be suitable for a use case in which it is necessary to avoid unused prefetches altogether.
Note that eager and immediate were synonyms in the initial SRA implementation, but that is changing. Keep an eye on the official docs for updates.
Speculations and new browser tabs
Initially, SRA launched without the ability to prerender pages that open in new tabs, as Etsy listings do. This option was added later, but only for values _blank of the target attribute of the link elements, not named target attributes such as the ones that Etsy uses, for example .
Fortunately, the target restriction doesn't apply to prefetching, so for SRA prefetching (unlike SRA prerendering) there's no problem, regardless of whether or how you specify a target at all. For developers who may be considering moving from prefetching to prerendering, this distinction is something to bear in mind.
5-minute rule
Because of the complex nature of listing pages, Etsy's HTML pages are non-cacheable. However, the speculative prefetch keeps the prefetched pages cached in memory for five minutes. This was a helpful learning, as there would be no point of using speculative prefetches at all if they expire immediately. After five minutes, the normal caching rules apply, set via HTTP headers such as Max-age or Expires.
Given that only two pages are currently kept in memory cache and all others expire because they are non-cacheable, the benefits are greatly reduced when, for example, a person hovers over 3 links and eventually clicks the first one which leads to a page that's already expired from the prefetch memory (and HTTP!) cache.
To aid with the two-page restriction, one strategy we devised is to make our pages cacheable for five minutes when we detect a prefetch request. Such requests are identifiable because the browser sends Sec-Purpose: prefetch HTTP header when prefetching. This helps preserve downloaded pages that would’ve otherwise expired from both memory and HTTP cache.
Video links and shadow DOM
Often, listings on Etsy include product videos, which start to play on the search results page when a user hovers their mouse over them. In these cases, prefetching doesn't work: the mouse hover is effectively "swallowed," disappearing into the shadow DOM of the browser's video player. One workaround is to overlay a div on top of the video for 200ms to let the hover register in the DOM. Then, after the 200ms has elapsed, remove the extra div to let the browser video controls (e.g., on right click) work as usual. You can find a demonstration of this technique here.
Cookies
If a page sets cookies, prefetching it will set those cookies as well (as demonstrated here). This is something to be aware of, as the prefetch may end up being unused. This may confuse your application (and/or analytics) to thinking a page has been visited where in reality it was not.
Again, you can use Sec-Purpose: prefetch HTTP header to detect prefetch requests and avoid setting the cookie as part of the prefetching process.
Redirects
If the link to the page being prefetched goes through a redirect, the actual page after the redirect is still being prefetched. Let’s say you have a sequence that looks like this:
Link on Page A - redirect - Page B
Here the browser follows the redirect during prefetching and still caches Page B. When the user then clicks the link on page A leading to Page B, the browser follows the usual process of going through the redirect. Normal HTTP cache rules still apply, meaning that if the redirect is cached, it won’t need to be requested again.
So, even though redirects are a bad performance practice, if you need to do them, they do not affect prefetching as long as you set appropriate caching headers.
Mutating hrefs
Sometimes the href attributes of elements get modified by JavaScript on mouse hover. This does not play well with prefetching. Imagine you have:
Follow me
… which changes on hover to:
Follow me
When the user hovers over the link, the browser starts working on prefetching link.html but realizes that the link to that page is no longer in the DOM and abandons the process. So the page is not prefetched even if ?source=footer doesn’t change the target page in any way other than reporting analytics. The browser has no way of knowing this and considers the two as separate pages.
Additionally, the failed attempt at prefetching link.html counts in the “two speculations only” rule and evicts the older speculative load from the memory cache. For best results, avoid modifying links on hover.
Analytics and Event Logging
This is the elephant in the room. Many sites on the web today were built in a world where prefetching did not exist. So there is one big assumption: that a page load is always initiated by the user and the load can be counted as such – either server-side during page construction or client-side by JavaScript after the page is loaded (or, as it often happens, a combination of the two). With prefetching, this assumption is no longer true. A page constructed on the server-side and downloaded by the browser does not necessarily mean the page has been seen (and therefore its JavaScript has been executed). This can result in a number of miscalculations when it comes to analytics.
Luckily, browser APIs such as the Sec-Purpose HTTP header and JavaScript APIs (document.prerendering and prerenderingchange event) allow us to tell prerender requests from user-generated ones, as well as when a prerendered page is "activated" (when the user actually sees a prefetched page). For prefetches, Performance Resource Timing’s deliveryType method of navigational-prefetch can be used for the purposes of analytics.
We (and our analytics partners) found this to be the hardest part: ironing out the required analytics updates so that numbers remain true after implementing speculation rules. In our particular use case, we intentionally pursued a strategy of prefetching the destination page instead of prerendering it, meaning that no assets would be loaded and JavaScript would not execute on our prefetches. This gave us a relatively simple way to handle the accuracy of our analytics.
A foundational piece of our analytics is event logging. For example, in the controller of the listing page we log a view_listing event that contains key information such as the listing ID, user ID, etc. This informs not only our site analytics, but also our search training pipeline, recently viewed listing data for users, and more. We ended up creating a system to cache the payload of all events within a request to avoid firing those events during prefetches. We were then able to move that event logging to the destination page’s JavaScript bundle, deferring them until after page “activation” and mitigating the impact of prefetching on our analytics.
Results
We were thrilled with the performance results of the prefetching experiment. We saw a 20-24% improvement in many performance metrics we care about: TTFB, DOMContentLoaded, FCP, LCP.

The 75th percentile time to first byte (TTFB) on the listing page improved by 23.6%
We saw similar improvements throughout the request: First Contentful Paint -20.7%, Largest Contentful Paint -21.1%, DOMContentLoaded -20.4%, and Page Load -10.6%

In the cumulative distribution function below, we see the control of our experiment (no speculation rules prefetches) in blue, and the treatment (speculation rules prefetches) in orange, with the treatment dramatically faster than the control at every percentile. Remarkably, about 40% of eligible browsers saw their TTFB drop nearly to zero:

We saw small but detectable improvements in some business metrics, which is promising given that listing page views come from many sources, only some of which are search results. As we implement more prefetching in more places, we hypothesize that the numbers will further improve.
When people approach SRA implementation they may be worrying about unused prefetches and resource waste. In our experiment we saw a ratio of about 14:1 for the number of prefetches requested to subsequently activated pages (i.e., about 1 in 14 prefetch requests was navigated to by the user).
We’re encouraged by these results, and are looking forward to new opportunities to improve performance across additional surfaces.
Opportunities to iterate and expand
One clear opportunity is to try implementing prefetching on other pages beyond Search. Shoppers end up on product listing pages from various other referral surfaces: shop pages, our SEO-optimized landing pages, home page, etc. Prefetching could improve performance on these surfaces, leading to a better experience for Etsy buyers.
Another opportunity is to consider upgrading our prefetching to prerendering in the future. This would be a significant change to client-side JavaScript code operating during prefetches. However (and it's hard to contain the excitement about this!) Chrome is working on prerender-until-script update, which means prerendering stops at the first . Even if you have high up in the of your page and prerendering halts early, the browser will still download page resources (scripts, styles, images, fonts) and have them ready.
For our use case, enabling prerender-until-script would mean that frontend performance metrics downstream of TTFB, such as First/Largest Contentful Paint, would likely see even larger improvements, and users would be able to interact with the listing page even earlier. This would further reduce friction for users when browsing on Etsy, letting them spend less time watching web pages load and more time engaging directly with our sellers’ amazing inventory of items.
Acknowledgements
Implementing SRA was truly a cross-team effort, not only by the search front-end and web performance teams but also people from infrastructure, analytics, ranking, and recommendations. Special thanks to Paul Calvano from our Web Performance team, Diana Sanchez Urban from Search Experience Web, and Eileen Toomer from the Visits team! This project also benefited from input from members of Recommendations and Listing Page teams, as well as members of our internal Architecture Advisory Group.

Source: https://www.etsy.com/codeascraft/search-prefetching-performance?utm_source=OpenGraph&utm_medium=PageTools&utm_campaign=Share

Reply