Early Hints (103) on Cloudflare

Between the moment a browser sends a request for a page and the moment the first byte of HTML arrives, the connection is idle. For a static page served straight from a CDN cache, that gap is tiny. For a cache miss fetched from a distant origin, or a page that passes through an edge function, it can be 100–400 ms — time in which the browser already knows, or could know, that it will need the site's stylesheet, a font and a hero image. HTTP 103 Early Hints lets the CDN tell the browser about those resources during the gap, so it starts fetching them before the HTML arrives.

This guide enables Early Hints on Cloudflare for a static documentation site whose HTML is sometimes fetched from an S3 origin, decides which resources to hint, verifies that browsers receive and use the hints, and measures when they help and when they do not. It is part of Resource Hints and Navigation Speed.

Prerequisites

  • A site proxied through a Cloudflare zone (or a Pages project, where Early Hints are on by default).
  • The critical resources for each template identified: main CSS, LCP image, critical font.
  • Field or lab data that shows a gap between navigation start and first byte (TTFB).

How Cloudflare Produces Early Hints

Early Hints need the resources to be known before the final response is ready. Cloudflare solves this by remembering them: when a response for a URL includes Link headers with rel=preload or rel=preconnect, Cloudflare caches those headers; on a later request for the same URL, it immediately sends a 103 with them, then fetches or serves the final response. The HTML itself does not need to be cached for this to work, which is what makes it useful on cache misses.

For Pages projects, Cloudflare also generates Link headers automatically from <link rel="preload"> and <link rel="preconnect"> elements in the HTML. For a zone in front of another origin, the origin (or a Transform Rule) must send the Link headers.

Request sequence for an HTML cache miss with 103 Early Hints The browser requests a docs page. The Cloudflare edge immediately sends a 103 with Link headers for the stylesheet, the font and the hero image, and the browser starts fetching them from the edge cache. Meanwhile the edge fetches the HTML from the S3 origin, which takes about 240 milliseconds for a distant reader. When the 200 HTML response arrives, the stylesheet and font are already downloaded. A cache miss with and without Early Hints Browser reader in Tokyo Cloudflare edge NRT Origin S3 Frankfurt GET /docs/guide/proxy/ 103 Link: css, font, hero (~5 ms) fetch hinted assets from edge cache fetch HTML (cache miss) 200 HTML (~240 ms) 200 HTML, assets already loaded
The hinted resources are hashed assets already cached at the edge, so they arrive during the origin wait.

The site's HTML lives in S3, which cannot vary headers per page on its own. Two options: set Link as S3 object metadata during upload (per page, from the build), or add them with a Cloudflare Transform Rule (per template, by path). The build already knew each page's critical resources, so it wrote them as metadata at upload time:

# during deploy, per HTML file (generated from the build manifest)
aws s3 cp dist/docs/guide/proxy/index.html s3://docs-bucket/docs/guide/proxy/index.html \
  --content-type 'text/html; charset=utf-8' \
  --metadata-directive REPLACE \
  --cache-control 'public, max-age=0, s-maxage=300, stale-while-revalidate=86400' \
  --metadata 'link=</_astro/base.Df3k2a.css>; rel=preload; as=style, </fonts/inter-400-700.woff2>; rel=preload; as=font; type="font/woff2"; crossorigin'

S3 returns user metadata as x-amz-meta-link, so a Cloudflare Transform Rule renames it to Link on the response. A simpler alternative for sites where every page shares the same critical CSS and font is a single Transform Rule that sets a static Link header for all HTML paths.

Step 2: Enable Early Hints and Verify

Enable Early Hints in the zone's Speed → Optimization settings (or early_hints: on via the API). Then verify with curl, which prints informational responses:

curl -sI --http2 https://docs.example.com/docs/guide/proxy/ | sed -n '1,6p'
# HTTP/2 103
# link: </_astro/base.Df3k2a.css>; rel=preload; as=style
# link: </fonts/inter-400-700.woff2>; rel=preload; as=font; type="font/woff2"; crossorigin
#
# HTTP/2 200

The first request after enabling returns only the 200 — Cloudflare has to see the Link header once before it can replay it. In Chrome DevTools, resources fetched because of an Early Hint show "early-hints" in the Initiator column. Chrome and Edge support Early Hints for navigations over HTTP/2 and HTTP/3; Firefox added support in version 120; Safari supports preconnect hints from 103 but not preloads at the time of writing.

Step 3: Choose What to Hint

Hints compete with each other and with the HTML for bandwidth. The site hints at most three resources per page:

  • The main stylesheet — render-blocking, so it directly delays first paint.
  • The body font — often the next thing that blocks text rendering.
  • The LCP image — only on templates where the LCP element is an image (landing pages), with fetchpriority=high in the hint.

Hinting all fonts, all scripts and several images was tested and made LCP worse on slow connections: the extra downloads competed with the HTML and with the LCP image. The same restraint applies to regular preloads, as in Auditing Unused Preloads.

Resources to include in and exclude from Early Hints A matrix of resource types. The render-blocking stylesheet should be hinted, as it delays first paint. The body text font should be hinted. The LCP image should be hinted only on image-LCP templates, with high priority. JavaScript modules for islands should not be hinted because they are not needed for first paint. Below-the-fold images and secondary fonts should not be hinted because they compete with critical resources. What to hint and what not to Resource Hint? Why Main stylesheet yes blocks first paint Body font yes blocks text rendering LCP image image-LCP templates only fetchpriority=high Island JS modules no not needed for first paint Other images and fonts no compete with critical ones
Three hints at most; everything else waits for the HTML as usual.

Preconnect Hints for Third-Party Origins

Early Hints can carry rel=preconnect as well as preloads, and for pages that must fetch from a third-party origin early — a font service, an image CDN on another hostname, an API the first interaction calls — a preconnect hint in the 103 lets the browser complete DNS, TCP and TLS for that origin during the idle time. The documentation site had one such origin, its image CDN on a separate hostname for screenshots. Adding Link: <https://img.example.net>; rel=preconnect to the hints cut the connection setup for the first screenshot by about 110 ms on cache-miss navigations. Safari, which ignores preloads in 103 responses, honours preconnects, so this was also the one Early Hints benefit Safari readers received. As with preloads, keep preconnects to the one or two origins the page genuinely needs early; each open connection has a cost on constrained devices.

When Early Hints Help and When They Do Not

Early Hints fill idle time before the HTML. They help in proportion to that idle time:

ScenarioIdle time before HTMLLCP change with hints
HTML edge cache hit, reader near edge~5 msnone measurable
HTML edge cache miss, origin in same region~40 ms−30 ms
HTML edge cache miss, origin far away~240 ms−170 ms
HTML through an edge function (auth check)~90 ms−70 ms

Once HTML caching at the edge was improved, as described in Improving TTFB for Static HTML, about 95% of navigations were edge hits and saw no benefit. Early Hints are therefore a complement to edge caching, not a substitute: they make the remaining misses less painful.

Measured Impact

Two weeks of field data with Early Hints off and on, split by HTML cache status (recorded via a Server-Timing header):

MeasureHints offHints on
LCP p75, HTML cache misses (5% of views)2.9 s2.7 s
LCP p75, HTML cache hits (95% of views)1.52 s1.51 s
FCP p75, cache misses1.9 s1.6 s
Share of navigations receiving a 103—81% (Chromium + Firefox)
Wasted hinted bytes (resource not used)—0 (only critical resources hinted)
Effect of Early Hints on LCP for cache hits and misses Paired bars. For HTML cache misses, LCP at the 75th percentile fell from 2.9 seconds to 2.7 seconds with Early Hints. For HTML cache hits, it stayed at about 1.5 seconds either way, because there was almost no idle time before the HTML. LCP p75 by cache status, hints off and on Hints off Hints on HTML cache miss 2.9 s 2.7 s HTML cache hit 1.52 s 1.51 s
Field data from web-vitals RUM, cache status from a Server-Timing header, two weeks per variant.

Pitfalls & Rollback

  • Expecting gains on cached HTML. There is no idle time to fill; fix edge caching first.
  • Hinting too many resources. Extra downloads compete with the HTML and the LCP image.
  • Hints for resources the page no longer uses. Stale Link metadata after a redesign wastes bandwidth; generate hints from the build.
  • Missing crossorigin on font hints. The hinted font is fetched twice.
  • Rollback: disable Early Hints in the zone settings; the Link headers can stay, since they also act as normal preload headers on the final response.

Conclusion

Early Hints let a CDN put the time before the HTML to work, starting downloads of the stylesheet, a font and the LCP image while the page is still on its way. On Cloudflare they are replayed from Link headers the site already sends. On a static site whose HTML is almost always cached at the edge, they change little; on the navigations that miss the cache or pass through an edge function, they cut hundreds of milliseconds of idle time. Hint only the critical few resources, generate the headers from the build, and treat them as a complement to good edge caching.

FAQ

What is a 103 Early Hints response?

An informational HTTP response sent before the final response, carrying Link headers for resources the page will need. Browsers that support it start preloading or preconnecting to those resources while the server or CDN is still preparing the final HTML.

Do static sites benefit from Early Hints?

Mostly when the HTML is not served instantly, such as on edge cache misses, when HTML is fetched from a distant origin, or when an edge function runs before responding. When HTML comes straight from the edge cache in a few milliseconds, there is little idle time for hints to fill.

How does Cloudflare generate Early Hints?

When Early Hints is enabled for a zone, Cloudflare caches Link headers with preload or preconnect from responses and sends them as a 103 on later requests for the same URL, before fetching or serving the final response. Pages projects also generate Link headers automatically from preload elements in the HTML.

Which resources should be hinted?

Only a few critical ones: the main stylesheet, the LCP image, and critical fonts, plus preconnect for any required third-party origin. Hinting many resources competes with the HTML itself and with each other.

Filed underHow-tosCloudflare