Chapter 56: Resource Hints & Preloading

Modern prerender & The Speculation Rules API

`<script type="speculationrules">`, document prerendering, zero-latency instant transitions, and eagerness policies.

LEARNING OBJECTIVES
  • Understand why legacy <link rel="prerender"> was deprecated and replaced by the Speculation Rules API.
  • Implement declarative JSON speculation rules using <script type="speculationrules">.
  • Configure speculation actions (prefetch vs prerender) with URL list rules and dynamic document rules (where selectors).
  • Master the 4 speculation eagerness levels: immediate, eager, moderate, and conservative.
  • Manage the prerender lifecycle in JavaScript using document.prerendering and the prerenderingchange event.
🎬 INTERACTIVE VISUAL PIPELINE Core Architecture Simulation
🌐
1. Input
Directives & Tags
⚙️
2. Parse
Tokenizer & AST
🌳
3. Layout
Box Model & Flow
🎨
4. Render
GPU Paint & Composite
PHASE 1: INPUT & DIRECTIVES
Browser receives declarative markup stream, parsing tag tokens and initializing component state.

📖 The Mental Model & Story (Intuitive Foundation)

Imagine an Olympic track relay race.

In a traditional relay, Runner 1 sprints the full 100 meters to the handover zone. Runner 2 stands completely still with feet planted on the track. When Runner 1 reaches the line and slaps the baton into Runner 2's hand, Runner 2 must accelerate from 0 km/h up to top speed. That acceleration phase loses valuable tenths of a second.

Now imagine a Flying Start. While Runner 1 is still 20 meters away, Runner 2 starts sprinting forward in the acceleration zone. By the exact moment the baton connects, Runner 2 is already moving at top speed (35 km/h). The handover is completely seamless, with zero velocity lost.

The Speculation Rules API is the browser's Flying Start:

  • Instead of waiting for a user to click a link before requesting HTML, CSS, JavaScript, and images, the browser creates an invisible, background browsing context (a hidden tab).
  • It downloads the full page, builds the DOM and CSSOM, executes scripts, and lays out the entire page in GPU memory.
  • When the user clicks the link, the browser activates the pre-rendered page instantly. Navigation time drops from 800ms down to 0 milliseconds (Instant Page Load).

Technical Deep Dive & Specifications

The Fall of Legacy <link rel="prerender">

In early HTML5, developers used:

<!-- ⚠️ DEPRECATED / LEGACY NO-OP IN MODERN BROWSERS -->
<link rel="prerender" href="/next-page.html">

Legacy prerendering had critical architectural flaws:

  1. Uncontrolled Resource Spikes: It lacked fine-grained rules, crashing mobile devices by spawning heavy background processes.
  2. Double Analytics Hits: Background prerenders counted as real page views on servers even if the user never clicked the link.
  3. No Intent Detection: It executed unconditionally without knowing if the user hovered, touched, or scrolled near the link.

Consequently, modern browser engines deprecated legacy <link rel="prerender"> (downgrading it to a basic No-Store prefetch or ignoring it entirely) and designed the Speculation Rules API.


The Architecture of the Speculation Rules API

The modern Speculation Rules API is declared via an inline JSON script with type="speculationrules":

<script type="speculationrules">
{
  "prerender": [
    {
      "source": "list",
      "urls": ["/checkout", "/account"]
    },
    {
      "source": "document",
      "where": {
        "and": [
          { "href_matches": "/articles/*" },
          { "not": { "selector_matches": ".no-prerender" } }
        ]
      },
      "eagerness": "moderate"
    }
  ]
}
</script>
+----------------------------------------------------------------------------------------------------+
|                               SPECULATION RULES JSON SCHEMA TAXONOMY                               |
+----------------------------------------------------------------------------------------------------+
| Field              | Allowed Values               | Technical Function                             |
|--------------------|------------------------------|------------------------------------------------|
| **Action**         | `"prerender"`, `"prefetch"`  | Whether to fully render page or only pre-cache.|
| **source**         | `"list"`, `"document"`       | Explicit array of URLs or CSS document rules.  |
| **urls**           | Array of URL strings         | Required when `source: "list"`.                |
| **where**          | Condition Object             | Filtering logic for `source: "document"`.      |
| `href_matches`     | Pattern string / Glob        | URL pattern (e.g. `"/blog/*"`, `"/product/*"`).|
| `selector_matches` | CSS Selector string          | DOM selector on `<a>` tags (e.g. `".quick"`).  |
| **eagerness**      | `immediate`, `eager`,        | Trigger threshold policy (see matrix below).   |
|                    | `moderate`, `conservative`   |                                                |
| **target_hint**    | `"_self"`, `"_blank"`        | Context target for activation.                 |
+----------------------------------------------------------------------------------------------------+

Eagerness Threshold Matrix

The eagerness property prevents wasted bandwidth by tying speculation triggers to real user intent:

Eagerness Level Trigger Condition Ideal Scenario Network / CPU Cost
"immediate" Triggers as soon as the Speculation Rules script is parsed. Fixed multi-step funnel with >90% conversion probability. High
"eager" Triggers with minimal delay once the link is in the DOM. High-confidence navigation links (e.g. primary CTA button). High
"moderate" Triggers on 200ms pointer hover (mouseover) or pointer down (touchstart/pointerdown). Blog lists, product grids, search results. Low / Optimal ⚡
"conservative" Triggers only on pointer down / mouse click initiation (mousedown). Complex, data-heavy sub-pages with uncertain clicks. Minimal

The Prerender Lifecycle & Restricted APIs

When a document is prerendering in the background, the browser strictly isolates it to protect user privacy and avoid disruptive behavior:

[Hidden Prerender Pipeline]
1. HTML Streamed -> DOM Built -> CSSOM Parsed -> JavaScript Executed -> Render Tree Boxed.
2. SENSITIVE APIS RESTRICTED (Audio, Video Autoplay, Notifications, Geolocation, alert(), prompt()).
3. document.prerendering === true
                                |
                [User Clicks Link on Active Page]
                                |
                                v
[Instant Page Activation]
1. Hidden tab swapped into primary viewport (0ms Paint Time!).
2. 'prerenderingchange' Event fires on Document.
3. document.prerendering becomes false.
4. Paused analytics, audio streams, and interactive timers resume.

JavaScript Lifecycle Handling Code Pattern

// Check if the current page is being executed inside a hidden prerender tab
if (document.prerendering) {
  console.log('Page is prerendering in background... Delaying analytics beacon.');
  document.addEventListener('prerenderingchange', () => {
    console.log('Page ACTIVATED by user! Firing analytics beacon now.');
    sendAnalyticsPageView();
  }, { once: true });
} else {
  // Standard direct navigation
  sendAnalyticsPageView();
}

SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
HTML STARSHIP CODE TERMINAL example.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...

💻 Interactive Code Playground

Starter Code

Line-by-Line Code Breakdown

  • Lines 8–22: Declares speculation rules using <script type="speculationrules">.
    • "source": "document" tells the browser to monitor all <a> anchor links rendered in the DOM.
    • where.and specifies that any link matching /article/* that does not possess the .external class should be prerendered.
    • "eagerness": "moderate" instructs the browser to begin prerendering as soon as the user's cursor hovers over the article link for at least 200ms or on touchscreen pointer down.
  • Lines 31 & 36: Internal article links that qualify for automatic background prerendering.
  • Line 41: External link with class="external", automatically excluded from prerendering.
  • Lines 49–62: JavaScript lifecycle monitor inspecting performance.getEntriesByType('navigation')[0].activationStart. If non-zero, the page was loaded from a pre-rendered background process with 0ms visual latency!

Expected Browser Render Output (DevTools Speculative Loads Tab)

Opening Chrome DevTools $\longrightarrow$ Application $\longrightarrow$ Speculative Loads:


SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
HTML STARSHIP CODE TERMINAL playground.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...
+----------------------------------------------------------------------------------------------------+
| Speculative Loads Inspector                                                                        |
+----------------------------------------------------------------------------------------------------+
| URL                               | Action     | Eagerness | Status    | Discard Reason            |
|-----------------------------------|------------|-----------|-----------|---------------------------|
| /article/quantum-computing        | Prerender  | Moderate  | Ready     | - (Hovered for 200ms)     |
| /article/web-performance          | Prerender  | Moderate  | Ready     | - (Touchstart detected)   |
| https://external-news.com         | -          | -         | Filtered  | Excluded by selector rule |
+----------------------------------------------------------------------------------------------------+
* User clicks link -> Status changes to 'Activated' -> LCP = 0.00ms 🚀

🏋️ Hands-On Exercise

🎯 The Challenge: Implement High-Conversion Speculation Rules

You are the lead performance architect for a documentation platform (https://docs.devplatform.io). Users frequently click through next/previous chapter buttons and sidebar links, but bounce rate increases if page transitions take longer than 400ms.

Requirements:

  1. Write a <script type="speculationrules"> block that:
    • Immediately prerenders the dedicated next-chapter link (#next-chapter-btn).
    • Uses moderate eagerness to prerender all internal documentation links matching /guide/*.
    • Uses conservative eagerness to prefetch (not prerender) heavy /api/* reference documentation links.
    • Strictly excludes any link containing the class .no-speculate or logout.
  2. Add the JavaScript snippet to ensure page analytics beacons (trackPageView()) only execute when the page is actively visible to the user.

🏁 Starter Code Sandbox

SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
STARTER CODE SANDBOX exercise.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...

⚠️ Common Pitfalls

  1. Prerendering Destructive or Stateful Endpoints: Never allow speculation rules to match actions like /cart/clear, /auth/logout, or /delete-account. The background browser process will trigger those actions silently!
  2. Double-Counting Analytics: If your analytics script executes on initial script evaluation without checking document.prerendering, you will record thousands of ghost page views for links users never actually visited.
  3. Overusing eagerness: "immediate": Prerendering 5 pages immediately can consume hundreds of megabytes of RAM and saturate the CPU, freezing the user's active page. Limit immediate to single, high-probability links.

💡 Pro Tips

  1. Dynamic Rule Injection: You can append speculation rules dynamically via JavaScript based on machine learning predictions or user interaction:
    const specScript = document.createElement('script');
    specScript.type = 'speculationrules';
    specScript.textContent = JSON.stringify({
      prerender: [{ source: 'list', urls: ['/checkout/step2'], eagerness: 'immediate' }]
    });
    document.head.appendChild(specScript);
    
  2. Inspect Activation Time in RUM: Capture activationStart in your Real User Monitoring (RUM) metrics:
    const navEntry = performance.getEntriesByType('navigation')[0];
    if (navEntry && navEntry.activationStart > 0) {
      console.log('Instant Activation Duration:', navEntry.activationStart);
    }
    
  3. Verify Prerender Status in DevTools: Use Chrome DevTools $\longrightarrow$ Application $\longrightarrow$ Speculative Loads to view live speculation pipelines, activation history, and rejection reasons.

📌 Key Takeaways

  • The Speculation Rules API replaces legacy <link rel="prerender"> with declarative JSON rules in <script type="speculationrules">.
  • Speculation rules support two core actions: "prefetch" (network cache only) and "prerender" (full DOM/CSSOM/JS background rendering).
  • Four eagerness levels (immediate, eager, moderate, conservative) link background work to real user intent.
  • Background prerendered pages have restricted APIs (no audio autoplay, no modal alerts, delayed geolocation).
  • Always protect analytics tracking by checking document.prerendering and listening for the prerenderingchange event.
  • --
⭐ LEARN: HTML 🌟 ⚔️ QUIZ BATTLE ARENA // ACTIVE
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 1 / 3

What happens to JavaScript execution when a page is prerendered in the background via the Speculation Rules API?

Question 1 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 2 / 3

Which Speculation Rules eagerness setting initiates a prerender when the user hovers their mouse over an anchor tag for at least 200 milliseconds?

Question 2 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 3 / 3

How can an analytics tracking script ensure it only records a page view when the user actually views a pre-rendered page?

Question 3 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP