Resource hints are instructions to the browser that you may use to improve a website’s performance. This set of instructions enable you to assist the browser in prioritizing origins or resources which need to be fetched and processed.
Let’s take a closer look at how resource hints are implemented, what are the most common pitfalls, and what we can do to make sure we are using resource hints as effectively as possible.
These may be implemented in one of two ways:
<link rel="dns-prefetch" href="https://example.com">
Link: <https://example.com>; rel=dns-prefetch
const link = document.createElement("link"); link.rel="prefetch"; link.href="https://example.com"; document.head.appendChild(link);
Adoption for HTTP headers is significantly lower than having resource hints implemented as part of the document markup; with less than 1.5% of the pages analyzed implementing resource hints through HTTP headers. This is likely attributed to the ease with which they may be added or modified from within the HTML source, when compared to adding an HTTP header on the server.
Using our current methodology, it is not possible to reliably measure resource hints that are added following user-interaction, such as those added through QuickLink, though that particular library featured on less than 0.1% of pages analyzed, according to the Core Web Vitals Technology Report.
Considering that the adoption of resource hints using HTTP headers is markedly smaller than adoption for the
<link> HTML element, the rest of this chapter will focus on analyzing the usage of resource hints through the HTML element.
There are five resource hint link relationships supported by most browsers today:
<link rel="dns-prefetch" href="https://example.com/">
dns-prefetch hint initiates an early request to resolve a domain name. It is only effective for DNS lookups on cross-origin domains and may be paired together with
preconnect. While Chrome now supports a maximum of 64 concurrent in-flight DNS requests—up from 6 last year—other browsers still have tighter limitations. For example, it is limited to 8 on Firefox.
<link rel="preconnect" href="https://example.com/">
preconnect hint behaves similarly to
dns-prefetch, but in addition to DNS lookups, it also establishes a connection together with TLS handshake if served over HTTPS. You are able to use
preconnect in place of
dns-prefetch as it gives a greater performance boost; but you must use it sparingly as certificates are usually upwards of 3 KB, which would be competing with bandwidth for other resources. You also want to avoid wasting CPU time opening connections which aren’t required for critical resource. Keep in mind that if a connection isn’t used within a short period of time (e.g., 10 seconds on Chrome), it would automatically be closed by the browser, wasting any
<link rel="prefetch" href="/library.js" as="script">
prefetch hint allows you to recommend to the browser that a resource might be required by the next navigation. The browser may initiate a low-priority request for the resource, possibly improving the user experience as it would be fetched from the cache when needed. While resource may be fetched in advanced with
prefetch, it will not be preprocessed or executed until the user navigates to the page which requires the resource.
<link rel="prerender" href="https://example.com/page-2/">
prerender hint allows you render a page in the background, improving its load time if the user navigates to it. In addition to requesting the resource, the browser may preprocess and fetch and execute subresources.
prerender could end up wasteful if the user does not navigate to the prerendered page. Contrary to the specification, Chrome treats the
Most modern browsers also support the
preload hint—and to a lesser degree, the
modulepreload hint. The
preload instruction initiates an early fetch for a resource which is required in the loading of a page and is most commonly used for late-discovered resources, such as font files or images referenced in stylesheets. Preloading a resource may be used to elevate its priority, allowing the developer to prioritize the loading of the Largest Contentful Paint (LCP) image for, even if this would otherwise be discovered while parsing the HTML.
modulepreload is a specialized alternative to
preload and behaves similarly, however its usage is limited to module scripts.
The most widely used resource hint is
dns-prefetch (36.4% on mobile); which is unsurprising, considering it was introduced in 2009. With the widespread use of HTTPS, in many cases you should replace it with
preconnect (12.7% on mobile), if you are certain that you will be connecting to that domain. Considering that the
preload hint is comparatively new, first appearing in Chrome in 2016, it is the second most widely adopted resource hint (22.1% on mobile) and is seeing constant growth year-on-year—a testament to the importance and flexibility of this directive.
As shown in the charts above, the adoption rates on mobile and desktop are near-identical.
You can observe that when segmenting the data by rank, the adoption rates change notably, with the
preload hint increasing from 22.1% for our whole data set, to claim the top spot with an adoption rate of 44.3% amongst the top 1,000 sites.
dns-prefetch is the only resource hint which exhibits a decrease in adoption when comparing the top 1,000 sites with the overall adoption.
To counter this decrease, the top 1,000 pages have an increased adoption for the
preconnect hint, taking advantage of its increased performance boost and wide support. I expect that the adoption for
preconnect will continue increasing as the rest of the internet follow suit.
Resource hints can be very effective if used correctly. By shifting the responsibility from the browser to the developer, it allows you to prioritize resources required for the critical rendering path and improve the load times & user experience.
Of the sites using resource hints, when comparing the median for the top 1,000 sites to the entire corpus, the top-ranking sites have more resource hints per page. The only hint which observes a different pattern is
prerender, which has a total of 0 occurrences in the top 1,000 sites.
By combining a page’s Core Web Vitals scores in the CrUX dataset and the usage of the preload resource hint, you can observe a negative correlation between the number of link elements and the percentage of pages which score a good rating on CWV. The pages which use fewer preload hints are more likely to have a good rating.
This same observation may be seen on a page’s LCP, indicating that in many cases, the developer is prioritizing resources which aren’t needed to render the LCP element and as a consequence degrading the user experience.
While this doesn’t prove that having preload hints causes a page to get slower, having many hints does correlate with having slower performance. Every page has its unique requirements and it is impossible to apply a “one size fits all” approach, but in the majority of cases the number of preloaded resources should be kept low and resource prioritization should be delegated to the browser when possible.
Note: In addition to the number of hints, the size of each preloaded resource has an impact on the website performance. The above figure does not take into consideration the size of each preloaded resource.
With that being said, and the expectation that more websites will adopt
preload, let’s take a better look at the preload resource hint and understand why it is so effective, yet at the same time so prone to misuse.
as attribute should be specified when using
rel="prefetch") to specify the type of resource being downloaded. Applying the correct
as attribute allows the browser to prioritize the resource more accurately. For example,
preload as="script" will get a low or medium priority, while
preload as="style" would be assigned an internal request priority of Highest. The
as attribute is required for caching the resource for future requests and applying the correct Content Security Policy.
script is the most common value by a significant margin.
<script> elements are usually discovered early as they are embedded in the initial HTML document, but it is a common practice to place
<script> elements before the closing
The second most commonly preloaded resource is the
font, which is a late-discovered resource since the browser will only download a font file after the layout phase when the browser knows that the font will be rendered on the page.
Stylesheets are ordinarily embedded in the document’s
<head> and discovered early during the document parsing. Additionally, as stylesheets are render-blocking resources they are assigned the Highest request priority. This should make preloading stylesheets unnecessary, but it is sometimes required to re-prioritize the requests. A bug in Google Chrome (fixed in Chrome 95) prioritizes preloaded resources ahead of other higher-priority resources discovered by the preload scanner, including CSS files. Preloading the stylesheet will restore its Highest priority. Another instance when stylesheets are preloaded is when they are not downloaded directly from the HTML document, such as the asynchronous CSS “hack” which uses an
onload event to avoid render-blocking the page with non-critical CSS.
Preload may be used to initiate a request to retrieve data which you know is critical to the rendering of the page, such as a JSON response or stream.
Preloading images may help improve the LCP score when the image is not included in the initial HTML, such as a CSS
crossorigin attribute is used to indicate whether Cross-Origin Resource Sharing (CORS) must be used when fetching the requested resource. This could apply to any resource type, but it is most commonly associated with font files as they should always be requested using CORS.
||< 0.1%||< 0.1%|
rel="preload" crossoriginattribute values.
The default value when no value is specified is
anonymous and this value will set the credentials flag to
same-origin. It is required when downloading resources protected by CORS. It is also a requirement when downloading font files—even if they are on the same origin! If you omit the
crossorigin attribute when the eventual request for the preloaded resource uses CORS, you will end up with a duplicate request since it won’t match in the preload cache.
Authorization header; setting the
crossorigin="use-credentials" attribute will include this data in the request and allow the server to respond to the request so that the resource may be preloaded. This is not a common scenario with 0.1% usage, however if your page content is dependent on an authenticated status, it could be used to initiate an early fetch request to get the login status.
An oft-neglected feature available to
rel="preload" is the ability to specify media queries through the
media attribute—with less than 4% of all preloads using this attribute. The
media attribute accepts media queries allowing you to target the media type and specific browser features, such as viewport width. As an example, the
media attribute would allow you to preload a low-resolution image on devices with a narrow viewport and a full-sized image on devices with a large viewport.
In addition to the
media attribute, the
<link> element supports
imagesizes attributes which correspond to the
sizes attributes on
<img> elements. Using these attributes, you can use the same resource selection criteria that you would use on your image. Unfortunately, their adoption is very low (less than 1%); most likely owing to the lack of support on Safari.
media attribute is not available on all
<link> elements as the spec suggests, but it is only available on
Owing to the versatility of
rel="preload", there isn’t a clear set of rules dictating how to implement the preload hint, but we can learn a lot from our mistakes and understand how to avoid them.
We have already seen that there is a negative correlation between a website’s performance and the number of preload hints. This relationship may be influenced by two factors:
- Incorrect preloads
- Unused preloads
An incorrect preload refers to when you preload a resource which is not as important as the other resources which the browser would have otherwise prioritized. We are unable to measure the extent of incorrect preloads as you would need to A/B test the page with and without each hint.
An unused preload occurs when you preload a resource which is not needed within the first few seconds of loading the page.
In such cases, the preload hint is regressing the website’s performance, as you are instructing the browser to download and prioritize files or resources which are not needed immediately—or even not needed at all. This is one of the challenges when using resource hints, as they require regular maintenance and automating the process opens the door to allow such issues to creep in.
Attempting to preload a CORS-enabled resource without including the correct
crossorigin attribute will download the same resource twice. The
crossorigin attribute is required on the
<link> element if the eventual request would also use CORS. This is also the case when requesting font files, even when self-hosting font files on the same origin, as font files are always treated as CORS-enabled.
More than half (63.6%) of the cases when the
crossorigin attribute on the
rel="preload" hint is either missing or incorrect, are linked to the preloading of font files, with a total of 14,818 instances across the dataset.
as attribute plays an important role when preloading your resources and getting this wrong may result in downloading the same resource twice. On most browsers, specifying an unrecognized
as attribute will ignore the preload. The supported values are
There are 17,861 cases of unrecognized values, with the most frequent error being omitting it completely; while the most common invalid as values are
stylesheet (the correct value is
When using an incorrect
as attribute value—as opposed to unrecognized value, such as using
style instead of
script—the browser will duplicate the file download as the request won’t match the resource stored in the preload cache.
video is included in the spec, it isn’t supported by any browser and would be treated as an invalid value and ignored.
More than 5% of pages which preload font files preload more font files than needed. When preloading font files, all browsers which support
preload also support
.woff2. This means that, assuming that the
.woff2 font files are available, it is not necessary to preload older formats, including
You can use resource hints to connect to, or download resources from, both first and third parties. While
preconnect are only useful when connecting to different origins, including subdomains,
prefetch may be used for both resources on the same origin and resources hosted by third parties.
When considering which resource hints you should use for third-party resources, you need to evaluate the priority and role of each third party on your application’s loading experience and whether the costs are justified.
Prioritizing third-party resources over your own content is potentially a warning sign, however there are cases when this is recommended. As an example, if we look at cookie notice scripts—which are required in the European Union by General Data Protection Regulation—these are usually accompanied by a
preconnect hint as they are highly obtrusive to the user experience and also a prerequisite for some site functions, such as serving personalized ads.
Analyzing the table above, 36.7% of all pages which include a
preload hint are preloading resources hosted on adservice.google.com. The s.w.org host is the most popular domain for
dns-prefetch and is used on WordPress sites (since version 4.6) for the loading of SVG images from its Twemoji CDN, when the browser is detected to not support native emoji characters. Google Fonts related services on
fonts.googleapis.com are the two most popular hosts for the
Google Fonts now includes instructions to
preconnect to both the fonts.gstatic.com origin and fonts.googleapis.com, which is usually good practice to offset the impact of these late discovered resources.
To learn more about the state of third parties, check out the Third Parties chapter.
Lazy-loading refers to the technique to defer downloading a resource—in this case an image or iframe—until it is needed or visible within the viewport. Native lazy-loading refers to the ability to specify this in the HTML with a
loading="lazy" for images is supported on most major browsers. On Safari, it is marked as in progress and is available behind a flag, but not yet enabled by default.
Lazy-loading of iframes is supported on Chrome, once again behind a flag on Safari but not yet supported on Firefox.
Browsers which do not support the
The percent of pages using
loading="lazy" has grown from 4.2% in 2020 to 17.8% by the time of our analysis. That’s a whopping 423% growth! This rapid growth is extraordinary and is likely driven by two key elements: the ease with which it could be added to pages without cross-browser compatibility issues, and the frameworks or technologies powering these websites. In WordPress 5.5, lazy-loading images became the default implementation, supercharging the adoption rate of
loading="lazy", with WordPress sites now making up 84% of all pages which use native image lazy-loading.
61.5% of lazy-loaded images on mobile and 63.1% of lazy-loaded images on desktop are actually within the initial viewport and shouldn’t be lazy-loaded. A study on the load times for pages which use lazy-loading indicated that pages which use lazy-loading tend to have a worse LCP performance, possibly caused by overusing the lazy-loading attribute. This is increasingly significant on the LCP element, which shouldn’t be lazy-loaded. If you are using
loading="lazy", you should check that the lazily-loaded images are below the fold and more critically, that the LCP element is not lazy-loaded. You may dig deeper into the effects of lazy-loading the LCP image on your Core Web Vitals in the Performance chapter.
The likelihood of a page containing at least one iframe is much lower than for that containing an image with only 2.6% of pages containing an iframe taking advantage of native lazy-loading. The benefits of lazy-loading an iframe are potentially important, as an iframe could initiate further requests to download even more resources, including scripts and images. This is especially true when using embeds, such as YouTube or Twitter embeds. Similarly, when deciding the loading strategy for an image, you must check whether the iframe is shown within the initial viewport or not. If it isn’t, then it is usually safe to add
loading="lazy" to the
<iframe> element to benefit from a reduced initial load and boost performance.
HTTP/2 supports a technology called Server Push that preemptively pushes a resource it expects the client will be requesting. As the server is pushing the resource instead of informing the client that it should request it, cache-management becomes complex and, in some cases, the pushed resources would even delay the delivery of the HTML, which is critical for discovering all resources required to load the page.
Unfortunately, HTTP/2 push has been disappointing, with little evidence that it provides the performance boost promised compared to the risk of over pushing resources that either the browser already has, or that are of less importance than resources the browser requests.
So, while the technology is widely available, overcoming these obstacles makes it highly unpopular—with less than 1% adoption. Chrome has also filed an Intent to Remove that is paused until a testable implementation of 103 Early Hints (covered next) is available. Chrome does not support Server Push on HTTP/3 either.
You can read more about HTTP, HTTP/2, and HTTP/3 in the HTTP chapter.
While there are no proposals to add new
rel directives, improvements from the browser vendors to the current set of resource hints—such as the prioritization bug in Chrome—are expected to have a positive impact. Hint adoption is expected to evolve, and the use of
preload should shift towards its intended purpose: late discovered resources.
Additionally, two proposals, 103 Early Hints and Priority Hints, are expected to be made available soon, with experimental support already available on Chrome.
Chrome 95 added experimental support for 103 Early Hints for
preconnect. Early hints enable the browser to preload resources before the main response is served and take advantage of the idle time on the browser between the request being sent and the response from the server. When using 103 Early Hints, the server immediately sends an “informational” response status detailing the resources to be preloaded using the HTTP header method, while processing the real document response. This way, the browser will be able to initiate preload requests for critical resources even before the HTML arrives and much earlier than it would if using the
<link> element in the document markup. 103 Early Hints overcomes most of the difficulties encountered with HTTP/2 Server Push.
Priority hints inform the browser of the relative importance of resources within the page, intending to prioritize critical resources and improve Core Web Vitals. Priority Hints are enabled through the document markup by adding the
importance attribute to resources, such as
importance attribute accepts an enumeration of
auto and by combining this with the type of resource, the browser would be able to assign the optimal fetch priority based on its heuristics. Priority Hints are available on Chrome 96 as an origin trial.
During the past year, resource hint adoption grew and is expected to continue growing as developers take advantage of these APIs to prioritize resources and improve the user’s experience. At the same time, browser vendors have continued calibrating these directives, evolving their role and effectiveness.
Resource hints could become a double-edged sword if the benefit for your users is not evaluated. Almost a quarter of preload requests went unused while the number of preload hints correlated with slower load times.
Resource hints are akin to fine-tuning a race car’s engine. They would not turn a slow engine into a fast one, and too many adjustments could break it. Yet, some small tweaks here and there would allow you to maximize it.
So once again, the mantra behind resource hints remains, “if everything is important, then nothing is”. Use resource hints wisely and don’t overuse them.