Find out how your server can send hints to the browser about critical subresources.
What is Early Hints?
Websites have become more sophisticated over time. As such, it's not unusual that a server needs to perform non-trivial work (for example, access to databases, or CDNs accessing the origin server) to produce the HTML for the requested page. Unfortunately, this "server think-time" results in extra latency before the browser can start rendering the page. Indeed, the connection effectively goes idle for as long as it takes the server to prepare the response.
Early Hints is an HTTP status code (103 Early Hints
) used to send a preliminary HTTP response ahead of a final response. This allows a server to send hints to the browser about critical subresources (for example, style sheets for the page, critical JavaScript) or origins that will be likely used by the page, while the server is busy generating the main resource. The browser can use those hints to warm up connections, and request subresources, while waiting for the main resource. In other words, Early Hints helps the browser take advantage of such "server think-time" by doing some work in advance, thereby speeding up page loads.
In some cases, the performance improvement to the Largest Contentful Paint can go from several hundred milliseconds, as observed by Shopify and by Cloudflare, and up to a second faster, as seen in this before and after comparison:
How to use Early Hints
The first step to take advantage of Early Hints consists of identifying the top landing pages, that is, the pages where your users typically start when they visit your website. This could be the homepage, or popular product listing pages if you have lots of users coming from other websites. The reason these entry points matter more than other pages is because the usefulness of Early Hints decreases as the user navigates around your website (that is, the browser is more likely to have all the subresources it needs on the second or third subsequent navigation). It's also always a good idea to deliver a great first impression!
Now that you have this prioritized list of landing pages, the next step is to identify which origins or subresources would be good candidates for preconnect
or preload
hints. Typically, those would be origins and subresources that contribute the most to key user metrics such as Largest Contentful Paint, or First Contentful Paint. More concretely, look for render-blocking subresources such as synchronous JavaScript, stylesheets, or even web fonts. Similarly, look for origins that host subresources that contribute a lot to key user metrics.
Also note that if your main resources are already using preconnect
or preload
, you may consider these origins or resources among the candidates for Early Hints. See how to optimize LCP for more details. However, naively copying the preconnect
and preload
directives from HTML to Early Hints may not be optimal.
When using these in HTML, you typically want to preconnect
or preload
resources that the Preload Scanner won't discover in the HTML—for example, fonts, or background images that would otherwise be discovered late. For Early Hints, you won't have the HTML so you may want to instead preconnect
to critical domains or preload
critical resources that perhaps would otherwise be discovered early in the HTML—for example, preloading main.css
or app.js
.Additionally, not all browsers support preload
for Early Hints—see Browser Support.
The second step consists of minimizing the risk of using Early Hints on resources or origins that might be obsolete, or no longer used by the main resource. For example, resources that are frequently updated and versioned (for example, example.com/css/main.fa231e9c.css
) may not be the best choice. Note that this concern isn't specific to Early Hints, it applies to any preload
or preconnect
wherever they might be present. This is the sort of detail that's best dealt with automation or templating (for example, a manual process is more likely to lead to mismatched hash or version URLs between preload
and the actual HTML tag using the resource).
As an example, consider the following flow:
GET /main.html
Host: example.com
User-Agent: [....] Chrome/103.0.0.0 [...]
The server predicts that main.abcd100.css
will be needed, and suggests preloading it using Early Hints:
103 Early Hints
Link: </main.abcd100.css>; rel=preload; as=style
[...]
A few moments later, the web page, including the linked CSS is served. Unfortunately, this CSS resource is frequently updated, and the main resource is already five versions ahead (abcd105
) of the predicted CSS resource (abcd100
).
200 OK
[...]
<HTML>
<head>
<title>Example</title>
<link rel="stylesheet" href="/main.abcd105.css">
In general, aim for resources and origins that are fairly stable, and largely independent of the outcome for the main resource. If necessary, you may consider splitting your key resources in two: a stable part designed to be used with Early Hints, and a more dynamic part left to be fetched after the main resource is received by the browser:
<HTML>
<head>
<title>Example</title>
<link rel="stylesheet" href="/main.css">
<link rel="stylesheet" href="/experimental.3eab3290.css">
Finally, on the server side, look for main resource requests sent by browsers known to support Early Hints, and respond immediately with 103 Early Hints. In the 103 response, include the relevant preconnect and preload hints. Once the main resource is ready, follow up with the usual response (for example, 200 OK if successful). For backward compatibility, it's good practice to also include Link
HTTP headers in the final response, perhaps even augmenting with critical resources that became evident as part of generating the main resource (for example, the dynamic part of a key resource if you followed the "split in two" suggestion). Here is what this would look like:
GET /main.html
Host: example.com
User-Agent: [....] Chrome/103.0.0.0 [...]
103 Early Hints
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script
A few moments later:
200 OK
Content-Length: 7531
Content-Type: text/html; charset=UTF-8
Content-encoding: br
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script
Link: </experimental.3eab3290.css>; rel=preload; as=style
<HTML>
<head>
<title>Example</title>
<link rel="stylesheet" href="/main.css">
<link rel="stylesheet" href="/experimental.3eab3290.css">
<script src="/common.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
Browser support
Although 103 Early Hints is supported in all major browsers, the directives that can be sent on an Early Hint differs per browser:
Preconnect support:
Browser Support
Preload support:
Browser Support
Chrome DevTools also has 103 Early Hints support and the Link
headers can be seen on the document resources:
Note to use the Early Hints resources, Disable cache
must not be ticked in DevTools as Early Hints uses the browser cache. For preloaded resources, the initiator will show as early-hints
and the size as (Disk cache)
:
This also requires a trusted certificate for HTTPS testing.
Firefox (as of v126) does not have explicit 103 Early Hints support in DevTools, but resources loaded using Early Hints don't show HTTP Header information which is one indicator they were loaded though Early Hints.
Server support
Here is a quick summary of the level of support for Early Hints among popular open source software HTTP server software:
- Apache: supported using mod_http2.
- H2O: supported.
- NGINX: experimental module.
- Node: supported since 18.11.0 for http and http2
Enable Early Hints the easier way
If you are using one of the following CDNs or platforms, you may not need to manually implement Early Hints. Refer to your solution provider's online documentation to find out if it supports Early Hints, or refer to the non-exhaustive list here:
How to avoid issues for clients that don't support Early Hints
Informational HTTP responses in the 100 range are part of the HTTP standard, but some older clients or bots may struggle with these because prior to the launch of 103 Early Hints they were rarely used for general web browsing.
Only emitting 103 Early Hints in response to clients that send a sec-fetch-mode: navigate
HTTP request header has should ensure such hints are only sent for newer clients that understand to wait for the subsequent response. Additionally, since Early Hints are only supported on navigation requests (see current limitations), this has the added benefit of avoiding needlessly sending these on other requests.
In addition, Early Hints are recommended to only be sent over HTTP/2 or HTTP/3 connections and most browsers will only accept them over those protocols.
Advanced pattern
If you have fully applied Early Hints to your key landing pages and find yourself looking for more opportunities, you might be interested in the following advanced pattern.
For visitors who are on their nth page request as part of a typical user journey, you may want to adapt the Early Hints response to content that is lower and deeper in the page, in other words using Early Hints on lower-priority resources. This may sound counter-intuitive given that we recommended focussing on high-priority, render-blocking subresources or origins. However, by the time a visitor has navigated for a while, it's very likely that their browser already has all the critical resources. From there on, it might make sense to switch your attention toward lower-priority resources. For example, this could mean using Early Hints to load product images, or additional JS/CSS that are only needed for less common user interactions.
Current limitations
Here are the limitations of Early Hints as implemented in Chrome:
- Only available for navigation requests (that is, the main resource for the top level document).
- Only supports
preconnect
andpreload
(that is,prefetch
isn't supported). - Early Hints followed by a cross-origin redirect on the final response will result in Chrome dropping the resources and connections it obtained using Early Hints.
- Resources that are preloaded using Early Hints are stored in the HTTP cache and retrieved from there by the page later. Therefore only cacheable resources can be preloaded using Early Hints or the resource will be double fetched (once by the Early Hints and again by the document). In Chrome, the HTTP cache is disabled for untrusted HTTPS certificates (even if you proceed to load the page).
- Preloading responsive images (using
imagesrcset
,imagesizes
ormedia
) are not supported using HTTP<link>
headers as the viewport is not defined until the document is created. This means 103 Early hints cannot be used to preload responsive images and may load the incorrect image when used for this. Follow this discussion on proposals on how to handle this better.
Other browsers have similar limitations and, as noted previously, some further restrict 103 early hints to preconnect
only.
What's next?
Depending on interest from the community, we may augment our implementation of Early Hints with the following capabilities:
- Early Hints for uncacheable resources using the memory cache rather than the HTTP cache.
- Early Hints sent on subresource requests.
- Early Hints sent on iframe main resource requests.
- Support for prefetch in Early Hints.
We welcome your input on which aspects to prioritize, and how to further improve Early Hints.
Relationship to H2/Push
If you are familiar with the deprecated HTTP2/Push feature, you may wonder how Early Hints differs. While Early Hints requires a round trip for the browser to start fetching critical subresources, with HTTP2/Push the server could start pushing subresources alongside the response. While this sounds amazing, this resulted in a key structural downside: with HTTP2/Push it was extremely hard to avoid pushing subresources that the browser already had. This "over-pushing" effect resulted in a less efficient usage of the network bandwidth, which significantly hindered the performance benefits. Overall, Chrome data showed that HTTP2/Push was in fact a net negative for performance across the web.
By contrast, Early Hints performs better in practice because it combines the ability to send a preliminary response with hints that leave the browser in charge of fetching, or connecting to, what it actually needs. While Early Hints doesn't cover all the use cases that HTTP2/Push could address in theory, we believe that Early Hints is a more practical solution for speeding up navigations.
Thumbnail image by Pierre Bamin.