Speculative Loading: The Future of Navigation

Introduction to Speculation and Speculation Rules API

The talk begins with an introduction to the concepts of speculative loading, which involves predicting which page a user might visit next to enhance load times. Quynh-Chi highlights traditional methods like prefetching and then introduces the new Speculation Rules API, which aims to offer a better experience. Speculation is explained as a series of suggestions to the browser, optimizing idle time without affecting current page performance. Different strategies like preconnect, DNS prefetch, and resource prefetch are discussed, along with their limitations concerning cache and cross-origin requests.

Speculation Rules API: Usage and Benefits

Quynh-Chi delves into the details of the Speculation Rules API, highlighting its JSON-based rules allowing more flexible preloading of resources. It enhances spec loading capabilities by allowing rules to match URLs and CSS selectors and providing varying levels of eagerness for speculation. This section outlines the API's experimental status, its availability in Chromium browsers, and how it complements existing resource hints like link rel prefetch. The differences between prefetching and prerendering are emphasized, showcasing how the API addresses previous limitations and how it benefits both navigation and performance optimizations.

Drawbacks and Considerations of Speculative Loading

In this section, the speaker discusses potential pitfalls of speculation, such as wasted resources if users do not navigate to pre-loaded pages, and stale content issues triggered by prerendered state changes. The importance of server-side detection to avoid unintended actions is emphasized. Quynh-Chi advises on prioritizing what should be prefetched or prerendered, highlighting the gamble in decision-making and the critical balance between benefits and potential wasted utility. Particular attention is drawn to security and privacy concerns, especially regarding cross-origin and cross-site requests.

Privacy and Cross-Site Prefetching and Prerendering

Quynh-Chi emphasizes the privacy implications of speculative loading, particularly with cross-site prefetches and prerenders. The section details how these actions might inadvertently share user information with third-party sites, despite the API's efforts to maintain privacy boundaries. Restrictions on cross-origin prerenders and the need to opt-in from servers are outlined, while clarifying the distinctions between same-origin, cross-origin, and same-site URLs. The broader picture addresses potential leaks of user behavior and browsing environment through speculation rules.

Live Demo and Conclusion

In the concluding part, Quynh-Chi demonstrates a live example of using the Speculation Rules API. This demo highlights practical usage and the impacts of various settings, emphasizing the importance of understanding and testing speculations using Chrome's developer tools. She showcases how to effectively utilize this tool for web performance improvement while being mindful of its restrictions and possible privacy implications. The session concludes with an invitation for feedback and informal discussions, closing the session that explored both the potential and the caution required when using the Speculation Rules API.

So when I submitted this talk, I tried to come up with a cute pun for the name.

And then when I started writing, I was like, is this actually future?

So I added some uncertainty, but, yeah, today I'm going to talk about how you can use speculation to make your pages load faster and sometimes why you shouldn't.

So you may have tried using prefetch or prerender in the past to speed up your page loads.

And found it a bit clunky.

So I'll talk about the new Speculation Rules API and how that might make it a better experience for everyone.

But first, let's talk about what speculation is.

We also talk about it as speculative loading, but I trip over words when I get excited.

So I am mostly just going to call it speculation today.

So in a web dev context, navigation speculation is the concept of predicting or speculating about which page a user might visit next, and then doing some of the work to load that potential next page before they visit it so that if they do navigate there, it loads much faster.

When you navigate to a page, your browser does a bunch of work.

First, it has to figure out where it's going to get data from.

So it does a DNS lookup on domain name.

And next, now that it knows what server it's going to talk to, it has to do a TCP handshake to open a connection to a server.

And then it has to do a TLS handshake so it knows how to secure the connection, or at least I hope it's doing that.

And now it's ready to request the HTML from the server.

And when the response comes back, it has to pass the HTML.

And work out how to paint to your screen in a nice, pretty graphical form.

And of course, as part of doing all that, it's also going to run scripts and request any other resources it needs.

So there are lots of stages between triggering that navigation and seeing the render page in your browser.

So you can get the browser to stop at a lot of different places along the way.

And that said, because this is just speculation about where you might go next, everything I'm about to list is a resource hint.

You're suggesting to the browser that this might be a good thing to do.

It's low priority and it's designed to take advantage of the idle time of the browser, so it doesn't slow down the user experience on the current page.

So I know Mandy covered some of this yesterday, so it's probably going to be revision for some of you.

But you can pre connect to a server if you think you'll need to download resources from there.

And that means doing the connection handshake in advance, so the connection is already open when you actually need to ask for something.

This is really standard and it's been supported in all major browsers for a long time.

And you just do it using, our favorite all purpose link element with a rel preconnect Or instead of html link element, you could use a link header.

But obviously, this is only going to make a difference for a cross origin request because you already have the connection open to your current origin.

And also, if you don't use the connection for 10 seconds, the browser will close it.

So you only want to pre connect if you're going to use that connection soon.

And you can pre connect to every origin you might possibly make a request to.

But if you have a lot of them, it's probably going to be a bunch of extra work and performance hits for connections you might not even end up using.

So you can also just do DNS lookup for everything in advance.

And that's a lot less work than actually doing the handshake, but it will still save you time later.

And then you can reserve the full pre connect for the most important origins.

And to tell the browser to do the DNS lookup, you use the link element again with rel dns prefetch.

You can prefetch resources, so that when the user navigates, the data is already loaded into the cache and you can go straight to rendering instead of having to wait for the download first.

And this is on a per resource level, so you can choose what sub resources to prefetch.

It depends on your site architecture and how you're trying to optimize it.

So maybe you're navigating to another page and you just pre fetched the HTML.

And that way, when the navigation is triggered, you can start fetching the sub resources earlier.

Or maybe you predict you'll need to fetch an image, or a JavaScript file, or a CSS file for the next navigation.

So you target that explicitly.

And of course, there is a rel prefetch attribute for a link element that will trigger this.

Or we can do it with a fetch call in JavaScript.

And at least one of those methods will work in any major browser.

But there are limitations to this.

Prefetched resources get stored in the HTTP cache.

If there are cache control headers that stop them from being cached, then it's just going to make things worse.

Because you're going to download them in advance, and then you're going to download them again on navigation.

And browsers also partition the cache by site.

If you prefetch a resource for a cross site navigation, you won't actually be able to access that from the cache once you navigate.

So you do have to be careful if you're using this.

And then you can go all the way to pre render next page.

So when the user navigates, all the work is already done in the background and the browser can display the next page instantly.

And obviously you want to be pretty sure about this because you don't want to waste all of the work and data transfer.

And you might think that you should use the link element again for this one with relic rel equals pre render and it does exist.

But you're wrong, because the sneaky thing about prerender is that it's only ever been supported in Chromium.

And the implementation of that link rel prerender in Chrome is not actually a real prerender.

And in an amazing coincidence, given what I'm talking about, the link rel equals prerender interface in Chromium has been superseded by the new Speculation Rules API.

And you should use that instead.

But before we go any further, I want to highlight that even though prefetching and pre rendering can make navigation faster for your users, it's not a substitute for optimizing your download sizes.

That data is going to be transferred whether you do it before or after navigation, so it's still subject to all normal constraints, like slow internet connections or data transfer limits, and you're still paying for the bandwidth.

I work in platform, so speculating gives you more power over how you work fetch resources, but you still have responsibility to get those resources right.

And I just want to make a note on terminology.

Sometimes when we talk about pre rendering, it's in the context of server side rendering, and that's where we run our code on the servers of pre rendered HTML instead of generating the HTML in the client.

The rendering I'm talking about today is the work done by the browser engine to render the visual presentation of the page.

And since it's basically just the Chromium based browsers that support prerendering at the moment, if I talk about Chrome, I just mean all of those Chromium browsers.

Chrome has built in a bunch of pre rendering features for the browser itself.

And they kick in if you type in a URL in the top bar, or you search for something, or use a bookmark bar.

And then Google also has this new Speculation Rules API, and the intention is to make it easier and more flexible for developers to trigger the same kind of pre fetch or pre render for their own pages.

So the first big caveat to note here is that this is still experimental and it's available in Chromium only.

So it works in Chrome and Edge and Opera, but there's no support in Firefox or Safari.

And as far as I can tell, both of those teams are still reviewing the proposal, with no timeline for support.

But the good thing about the API is that it is progressive.

So you can use it now and browsers that don't support it would just ignore it.

And then you can use feature detection to fall back to link rel prefect in those browsers.

So what's different about using the new Speculation Rules API?

Let's talk about how to decide what to pre fetch or pre render.

The link element is pretty basic.

You pass it the address of a resource and it gets that resource.

So as a developer, you have to know exactly what resources you're targeting and list them explicitly.

You're also the one who has to predict where a user is going to navigate to next and decide when to actually trigger a pre fetch.

For example, you might, base it on user behavior and manually inject a tag when the user hovers or clicks the link, or you might use your existing navigation method metrics to say 99 percent of people visit this link from this page.

So it's worth triggering the prefetch or prerender for that when we load this document.

And you can even use AI to make predictions.

The speculation rule syntax is more flexible.

The browser can do a lot of the work of deciding what to load for you.

So as suggested by the name, you use JSON to define rules that tell the browser what to spec load.

And you can still match exact URLs that you specify yourself, but you can also give it rules about how to match links in the current page.

So it will scan over all the anchor and area tags in the document to look for links and find the ones that match the rules.

You can pattern match URLs and match by CSS selector, and you can combine and negate the conditions as well.

So for example, you could easily say, speculate on all links, except these ones that are marked with a particular class, and that's much nicer than having to create a link element for each URL explicitly.

And then you can also set the eagerness for each rule.

And that's where the API makes it easier to specify when to trigger the prefetch or prerender, because you can hint how important it is to do that and let the browser take care of it.

And you can set this to immediate, to say you think this is really important and the browser should probably grab it ASAP.

Right down to conservative, which is where you want to minimize resource wastage and the browser should only start the spec loading when the user is actually already clicking on the link.

And in the middle, it could trigger on hover, or when the link scrolls into view, or anything the browser thinks increases the likelihood of navigating to that link.

And so the browser will combine its own heuristics with the eagerness level you specify to choose what speculations it makes.

You should consider the characteristics of your site when you're choosing how eager the speculation should be.

If your page is just static HTML, speculating on that is going to create a lot less overheads.

Then if you have really heavy pages with a lot of JavaScript, where you might want to be more conservative because the impact of that potential waste of work is higher.

You can insert this JSON config directly into the page with a script type equal speculation rules element, or you can put it in a file and specify it using a speculation rules header.

So you can use this API without having to change the document itself.

And you can easily attach the same set of rules to every response using that.

Okay, so that deals with when to speculate, but what is new about the actual prefetch and pre render?

If you pre render using the speculation rules API, Chrome does a full pre render.

And that's a big deal because I mentioned before that pre render has only ever been supported in Chrome.

And originally when it was introduced, it would pre render the full page in the background and swap it in.

But that turned out to be too resource heavy and inflexible in the way it was implemented.

And they replaced it with a slightly fancier prefetch, which is what actually gets used if you use link rel equals prerender.

So the term pre render in that link rel prerender is actually a lie.

Chrome will start the rendering process to work out what sub resources the page needs and prefetch them, but it won't actually go ahead and render the page or run any scripts until the user loads the page.

And now the speculation rules API is bringing back that full prerender.

So what's actually happening in Chrome when it pre renders a page this way, is that it's rendering everything in an invisible tab using a per document in memory cache.

And when the user navigates to that pre rendered page, the browser just makes that invisible tab active.

And the experience for the user is that the page loaded instantly because it was already rendered and everything was in memory.

Even if the page hasn't finished loading before the user navigates, the browser will make that tab active immediately and just continue rendering from where it was at.

And since it's already partially loaded, the user doesn't have to wait as long for it to load from scratch.

Because this method actually renders the page and executes most JavaScript, it's also able to load resources, sub resources that are loaded via JavaScript, unlike the fake link pre render.

Prefetch by the new API uses the same approach as pre render to download the documents, but it stops earlier in the process.

Since this API is designed specifically for navigation, it avoids some of the issues with the other more general prefetch interfaces.

So since it uses an in memory cache instead of the HTTP cache, it doesn't get blocked by the cache control headers, but it can still also put its results in the HTTP cache if the headers are suitable.

And since we know it's for navigation, we can sometimes use it to help with cross site navigation, which we can't do with the other prefetches, although this is still limited for privacy reasons.

I'll come back to that a bit later.

Another benefit of using speculation rules is that the browser has a lot of control over how to prioritize the speculation.

So Chrome will look at what else is going on and what resource constraints exist.

So is your computer in battery saver mode?

Do you have data to say to move on?

Is your internet connection really slow?

Are you lower memory?

There's a whole list of reasons.

And then it also has limits on how many speculations it would do at a time.

So for example, if your speculation is triggered by user interaction, it will cancel older speculations as new ones are triggered because the user is more likely to follow the link they're currently interacting with.

But as a developer, you can just use speculation without having to worry about any of this.

One drawback of speculation rules pre fetch is that it can't pre fetch sub resources because it's a document based pre fetch and it doesn't parse the document.

So it doesn't know what sub resources it wants.

So if you need to do that, you still need to use link rel pre fetch or JavaScript fetch and specify the sub resources explicitly.

Another trade off of speculation rules being designed for navigation between documents is that it makes sense to use it for multi page apps, but it doesn't work for Single Page Apps.

Single page apps don't do real page navigations that the browser manages.

Even if they're using a router that makes it look like the page URL is changing.

They only fetch new data to render within the current document.

So you could pre render the single page app itself from a previous page, and that could help with the initial load time of the app.

But you can't use speculation rules for navigations within it.

That would be another time that you'd probably want to use link rel pre fetch at the resource level.

And for example, you could pre fetch a split JavaScript bundle to use on the next route change.

What are some of the things you need to look out for when speculating?

So spec loading is a bit of a gamble.

If it works out well, it can have great benefits, and your users will love you for making their experience so fast.

But if you load the wrong things, it will cost you and your users in wasted data transfer, resource usage, and potentially extreme confusion.

The obvious case is if the user doesn't end up visiting that page next.

Everything else you pre fetch or pre render gets discarded from the in memory cache if you navigate to a different page, and this is very scary to me.

So if you pre render two possible next destinations from the current page, at least one of those is going to be thrown out on navigation.

And maybe both.

It doesn't matter if there would have been a subsequent navigation to the other page, the cache pre render is already gone.

If your prerender stored anything in the HTTP cache, that will still be there.

So maybe it wasn't a complete waste of work, but you still probably want to avoid a wasted prerender because it's doing so much background work.

You might decide you're okay with Scenario for a prefetch because it's much lighter in resources.

But the page itself might also change before it's loaded.

So you're pre rendering a page that depends on service state.

Imagine that you're on a forum and your browser pre renders a forum thread.

And another user posts a new comment after the thread gets pre rendered.

And then you navigate to the pre rendered page and the comments are out of date.

That doesn't seem that bad, you're just a comment behind, but what if you're a forum admin moderating the comments?

Your admin controls pre render the thread, you delete a comment, and if you navigate back to the pre rendered thread and see the comments you've deleted, that's super confusing.

And that applies for state that's changed by the user as well.

So you visit a website and it's in dark mode and light mode is much better.

So you click the button on the site to change to light mode, which saves your preference without reloading the page.

Then you navigate to the next page, but it shows up in dark mode because it was pre rendered before you changed to light mode, and that's confusing too.

So the recommendation for this kind of situation is that pages should know how to refresh themselves if the state might change.

You won't always have that kind of control over the pages that get pre rendered, so you need to be aware this could happen.

But it gets worse.

The examples I just gave are about the user seeing an inconsistent state.

So they were bad, but mostly confusing to the user.

But another pattern where it's not safe to pre fetch or pre render is when making a request for that page, initiate some action or has some effects that you don't want to trigger until you actually navigate there.

For example, you're logging user out, changing language, using up free articles in the paywall site, or deleting the database.

So if you have control over the server, those pages are coming from, you can detect that the request is because of a prefetch or prerender and defer those actions until the navigation actually happens.

And so there are also a number of web and browser APIs and features that are deferred or restricted when pre rendering by default, because they also trigger behaviors that you aren't going to want to activate until the navigation happens.

Things like playing audio or video, showing a dialogue or request information using the clipboard.

But then of course there are the privacy implications.

So I already said that there are limitations on cross site speculation and that we come back to more details on that.

So as I mentioned before, unlike the link role prefetch, you can use speculation rules prefetch for some cross site prefetches, but I've mentioned cross site and cross origin a couple of times.

So for anyone who needs a clarification reminder on what the difference is, we'll have to look.

So this is a URL, obviously, and let's ignore the part on the end and the bit that's left is origin.

And the origin is made up of a scheme, a host name, and a port.

And if all of those are the same between two URLs, they're same origin.

Remember that the port might be implicit.

So like 443 is the default port for HTTPS.

So this would still be same origin.

But if any of those parts are different, it's cross origin.

So all these URLs at the bottom would be cross origin compared to the top one and each other.

And now if you think of a registered domain, which is one you can register, it's the name you pick plus a public suffix.

So that might look like bunniesarecool dot com or bunnerfesto dot dev but also something like qcisawesome dot net dot aum or qcn dot github dot io.

So that public suffix can be multiple parts.

And for the first URL here, the registrable domain is manifest dot dev.

For the second one, it's qcn dot github dot io.

And github is a part of the suffix in this case, because github gives out yourname dot github dot io addresses to people.

And for this last one here, it's still just  qcn And that registrable domain is the site for URL.

So these last two URLs are same site, but they're cross site with the first one.

Obviously, cross site is always cross origin.

And going back to our examples from before, we can see that same origin is always same site, but we can have same site cross origin URLs.

So now getting back to speculation, the reason all this matters is because the site is a boundary for privacy and the origin is a boundary for security.

So at the moment, cross site prefetches will only work if there aren't already cookies set for the destination.

This prevents sites from tracking user activity through prefetches using existing cookies.

Same site prefectches are fine, because you're already on the site that owns the cookies.

The Chrome devs say that in the future, servers will be able to opt in to cross site prefetches, but that's not a thing yet.

For pre renders, you have to opt in from the server side to do cross origin same site pre renders, and you can't do cross site pre renders at all.

But, even with the built in limitations, there are still privacy considerations when you're speculating.

If you're prefetching a page, you're still giving the destination server information about who you are and what page you're currently browsing.

The fact that you're prefetching at all could reveal information about your setup.

We talked about how speculation is blocked in data saver mode, for example.

So if you're speculating, that means you're not using that mode.

And if the speculation rules are based on analyzing your activity, And predicting where people like you go next, you could be leaking information about how you use the internet too.

So you do have to be careful when you're thinking about the privacy trade offs you're making because the API alone won't protect you from everything.

That's why extensions like uBlock Origin block speculation by default.

And I can guarantee that most uBlock Origin users are not trolling through the settings and deciding to allow prefetch to improve navigation performance.

So I really want to reiterate that you should not be relying on speculation for your performance because not all browsers support it.

It might be turned off for privacy reasons.

A browser might not take the hint because it already has performance issues.

And by relying on it, you might actually be making things worse.

This isn't to say you shouldn't use it ever, but think about the trade offs and other techniques you can use along with it.

All right, now that I have sufficiently scared you off using this, it is live demo time.

I think if you want to use this kind of feature, it's really important to see how it's working, and I'm not going to get into analytics and web performance metrics today, but Chrome has brought in some pretty good dev tools to help debug speculations, so hopefully this works.

I've heard and seen the live demo horror, sorry.

And I'm also awkwardly turning around now.

So I just want to do the simplest thing to show this in action.

And I've checked a few big photos on the page and we're going to load it with and without pre render.

So the first thing I'm going to do is just turn off the caching and simulate my home internet so that it actually takes a while to load and if this all goes well, you'll see the speed difference.

So the first thing I need to do is, is this big enough for people to see?

All right.

So make sure preloading is enabled in Chrome.

So here are the Chrome performance settings.

And if I scroll down to the bottom here, so that's off.

And as I mentioned, Ublock Origin blocks this feature for privacy.

So if I go to the Ublock Origin settings.

I can let it through.

And now if I go back to those Chrome performance settings, it is turned on.

Great.

Alright, so I'm going to load these photos of Aurora from May and hopefully the internet is working.

Great.

Alright, so as you can see it's taking a while to load the page.

So I'm just going to wait for that to load a little bit, so I can prove that it loads.

And then, just to prove that the cache is actually disabled, I'm going to refresh the page, and it's loading slowly again.

Okay, so it's not cached.

So I've made another page here that I added some speculation rules to.

And if we go look in the source here All right, so I have, put them in the script tag and I've got a few rules in here.

I've got an eager prerender rule on the prerenderme selector and a moderate prerender rule on links with Aurora in them and an immediate prefetch rule on the prefetchme selector.

And at the moment Chrome treats eager and immediate the same.

So these should both happen as soon as possible.

And looking at the links in the page up here, and I have annotated them on the left as well.

There's some that match each of those rules.

And one of those links there is to the page we were looking at before, which was like the one from May.

Now, if I open up the network tab, you can see there's a request here for one of the links I prefetched because it was an immediate prefetch and I can see here, it has a prefetch type on it.

And if I headers for this.

Please click, no, good computer.

Now scroll down to the request headers and you can see that there is a sec purpose prefetch header.

So that's telling the server it's a prefetch can detect that.

I had an eager pre render as well but you can't see that in here.

Because the Pre render happens in a background renderer.

But if I go to the dropdown up here, it shows me the other renderers, and I can pick that pre render one, and it shows me the network requests that it made.

So let's go back to that main renderer for the current page, and we only have one prefetch request there.

But if we look at the source again, come back.

You can see that there were two prefetch links there.

So what happened to the other one?

And this is where the speculation dev tools come in handy.

So if we go to the application tab over here and under background services, there's this speculative loads thing, heading, heading.

And when I click on it, I get a summary of circulation for this page.

So it tells me that this page was not spec load itself.

And it tells me about, some speculations initiated by the page.

And it says there's one failure and there is a link to the rules and speculations.

So if I go to the rules, it just shows you that there's one set of speculation rules.

And if I click on that, it shows you where I define them.

And we've seen those already.

It's not very interesting.

So we'll go back here and have a look at the speculations themselves.

And this is more interesting.

So it shows me, I'll make this a bit.

Let me go here.

Okay.

So it showed me a list of URLs and it shows me whether each of them is a pre render or a pre fetch and the status.

So there's a ready pre fetch.

So we saw that one in the network tab and we've got a ready pre render and we saw that one in that background renderer.

And this pre fetch failed.

So I can click on that for more details and it will tell me exactly why.

So I usually run about a thousand Chrome tabs at a time.

So while I was writing this talk, there were a few times it told me fail, it failed because Chrome was under extreme memory pressure.

But in this case, I'm making a prefetch request to the ABC website.

And I actually visited that site earlier.

So now Chrome is refusing to prefetch the page because I have cookies there already, like we talked about before.

But if I open up an incognito window, I won't have cookies.

And so if I open up the same page again, no, I made a new window and serving that's why, making the, actual incognito window.

All right, that's better.

All right.

So if, I open up the same page again, I have three success.

And I can see them, so the prefetches are ready, and I've got both my prefetches here.

So that worked.

Alright, so that's cool.

What about the other three links here, the ones we haven't looked at yet?

So they all have Aurora in the URL, these three.

And so they should all match the moderate prerender rule.

And you can see them on the list there, they're not triggered.

And moderate means they should start pre rendering when I hover over them for a bit.

So let's do that on the first one.

And so it said running and then it went to ready.

And I can do that again for the next one, same thing should happen.

Okay.

And now I'm going to hover over the third one, but let's watch that status column.

Okay, so that one ran.

The May one changed to failure.

And we can go look at the details there.

And it's telling me that this non eager pre render was automatically canceled because I started another non eager pre render and that's those Chrome limits kicking in.

You can only do two moderate or conservative periods at a time, and it will cancel the older ones when you trigger a new one.

All right.

So let's go trigger it again.

And now we can go back to the network tab and have a look at what that render is doing in the background there.

And so you can see the photos loading in the background renderer.

Alright, and that looks like it's finished now.

We can go click on the link.

And the page loads almost instantly.

Coming back here.

All right, so that's all I have for you today.

Thanks again for coming along.

I'd really love to get any feedback you have on my talk.

So the QR code will take you to a form for that.

Otherwise you can find me in these places.

If you'd like to chat about Vim or light mode or chasing auroras, or come find me at lunch.

That's it.

not that kind of speculation

An image of a person with a smooth, featureless face in a suit, standing with crossed arms against a backdrop of fluctuating stock market numbers. There is also a prominent upward orange arrow and the word "stonks" written across the image.

What is speculative loading?

  • aka navigation speculation
  • It's about the future
  • Predict where people will go next and do the work before they navigate

how is navigation formed

navigation
browser
DNS server
web server
Diagram illustrating a stick figure interacting with a browser represented by a large vertical rectangle, which in turn interacts with a DNS server and a web server, both represented by smaller rectangles.

how is navigation formed

Diagram showing the flow of navigation from a user to a browser, then to the DNS server and web server. Includes a stick figure representing the user, with arrows indicating navigation and DNS resolution processes.

how is navigation formed

Illustration of a navigation process flow. A stick figure sends a navigation request to a browser, which processes DNS resolution, TCP handshake, TLS handshake, HTTP requests, and HTTP responses between a DNS server and a web server.
/section>
On top of the previous slide we have a loaded page in a browser window.

Preconnect

  • Potential request
  • DNS resolutionDNS server
  • TCP handshake
  • TLS handshake (please)
get ready with me
Diagram showing a stick figure with a request leading to a browser, which connects to a DNS server through DNS resolution, performs a TCP handshake, and a TLS handshake with a web server. The process ends with "ready to make requests!" followed by a celebratory icon.

Preconnect

<link rel="preconnect" href="https://bunnifesto.dev" />
or HTTP header: Link: <https://bunnifesto.dev>; rel="preconnect"

DNS prefetch

get ready with me
Illustration showing a DNS prefetch process with a stick figure, browser, DNS server, and web server. Arrows indicate potential request, DNS resolution, and readiness to connect.

DNS prefetch

<link rel="dns-prefetch" href="https://bunnifesto.dev/" />
or HTTP header: Link: <https://bunnifesto.dev/>; rel="dns-prefetch"

Resource prefetch

potential request

browser

DNS resolution DNS server

TCP handshake

TLS handshake (please)

HTTP request/response for this resource web server

get ready with me

ready to render

Diagram showing a resource prefetch sequence from potential request to rendering, involving steps like DNS resolution and TLS handshake between a browser and servers.

Resource prefetch

browser
<link rel="prefetch" href="cute-bunny.jpg" />
or JavaScript: fetch("cute-bunny.jpg", { priority: "low" })

<link rel="prefetch" ...> bewares

  • It uses the HTTP cache, so…
    • Cache-Control: no-cache, Cache-Control: no-store are problematic
    • HTTP cache partitioning prevents cross-site prefetch
get ready with me

Prerender

  • navigation
  • DNS resolution to DNS server
  • TCP handshake
  • TLS handshake (please)
  • all the HTTP stuff
  • page render
  • ready for display!
get ready with me
Diagram of a stick figure interacting with a browser and server, involving processes like DNS resolution, TCP handshake, TLS handshake, HTTP request, and page rendering.

Prerender

<link rel="prerender" href="coolest-page.html" />
the previous slide partly obscured by a meme image with text 'WHAT A COINCIDENCE'.

Speculation Rules API

the previous slide partly obscured by a large yellow starburst with "Speculation Rules API" covers part of the diagram.

optimize your file sizes!

no, really, optimize your file sizes or I'll haunt you

Remember, with great power comes great responsibility.

Uncle Ben from Spiderman sitting inside a vehicle, looking slightly to the side with a serious expression.

some housekeeping

IT'S CHROMEEEEEE

Image of Elphaba from Wicked, wearing a pointed hat, with arms outstretched holding a broom, against a blue-lit background.

how do you decide what to speculate on?

heuristics? metrics?

speculation rules!

Speculation rules

  • JSON configuration
  • Exact URLs (like the other interfaces)
  • Pattern-match on links in the document
  • CSS selectors
  • Eagerness level
    • immediate > eager > moderate > conservative
    • consider how resource-heavy your site is

Speculation rules


  <script type="speculationrules">
  {
    "prefetch": [ ... ],
    "prerender": [ ... ],
  }
  </script>
  

or HTTP header:

Speculation-Rules: "/path/to/rules.json"

Mom, can we have Prerender?

No, we have

<link rel="prerender">
at home
<link rel="prerender">
at home: NoState Prefetch
this isn't even my final form
Image of a cartoon scene from the Simpsons where Milhouse holds POGs marked "PRERENDER" and another image shows Google Chrome logos on POGs labeled "PRERENDER".

Speculation Rules prerender

Slide with a stick figure next to a window titled "QC’s Bunnifesto," containing whimsical text about a "manifesto" and a link. The other half of the slide is a purple abstract shape with the text "~the veil of darkness~ (background/invisible)." The title is "Speculation Rules prerender."
The previous slide with an arrow pointing from the manifesto page to theinvisible tab labelled "speculative prerender"

foreground/visible

A stick figure next to a screenshot of a web page titled "A very cool page - Mangosoft Internet Chrome 2024," displaying a decorative line of snowflakes and ice cubes, with the word "voila!" beside a stylized lightning bolt.

Speculation Rules prerender

  • Uses per-document, in-memory cache
  • Instantly activate background-rendered tab
  • Partial prerender works too
  • Can load subresources via JavaScript

Speculation Rules prefetch

  • Same in-memory approach as prerender
  • In-memory cache avoids Cache-Control header issues
  • Still populates the HTTP cache
  • Can sometimes be used for cross-site navigations (more on that later...)

the browser knows things you don’t

Speculation Rules trade-offs

  • No subresource prefetch (obviously prerender does this)
  • Multi-page apps/real navigation only

Speculation Rules trade-offs

  • No subresource prefetch (obviously prerender does this)
  • Multi-page apps/real navigation only

who’s that pokémon?

Image of a silhouetted unknown Pokémon character with a question mark and the Pokémon logo on a background of red and blue.

it just wants to hug you

Illustration of Bewear, a pink and black bear-like character from Pokémon, with its arms raised against a dynamic blue and red background.

everything you cached gets discarded when you navigate elsewhere

something you prerendered might change!

QC gives an example of a message board and describes what might fo wrong with prerenderig.
Slide showing a comparison between dark mode and light mode view of a website called "Great Things Site" with an element labeled "prerender" pointing between them.

it's the impurity of the thing

your speculation could have side effects

An emoji of an eye centered on a slide.
https://www.bunnifesto.dev:443/about/
site vs origin
https://www.bunnifesto.dev:443/about/
origin

https://www.bunnifesto.dev:443/about/

scheme hostname port
An illustration of a URL dissected into parts: scheme, hostname, and port. Each part is labeled and underlined.

same-origin

https://www.bunnifesto.dev:443/about/

scheme

hostname

port

https://www.bunnifesto.dev:443/bun/ny.jpg

scheme

hostname

port

same-origin

https://www.bunnifesto.dev:443/about/
scheme hostname port

https://www.bunnifesto.dev/bun/ny.jpg
scheme hostname

site vs origin
Illustration showing two URLs underlining their scheme, hostname, and port, with an arrow noting "HTTPS = implicit port 443".

cross-origin

https://www.bunnifesto.dev:443/about/
scheme hostname port

https://bunnifesto.dev/talks/
https://www.bunnifesto.dev:1234/admin/
http://www.bunnifesto.dev/insecure.png

site vs origin

registrable domains

registrable domains

bunniesarecool.com

bunnifesto.dev

registrable domains

https://www.bunnifesto.dev:443/about/
https://qcn.github.io/secretpage.html
http://why.so.many.subdomains.qcn.github.io/

registrable domains

https://www.bunnifesto.dev:443/about/

https://qcn.github.io/secretpage.html

http://why.so.many.subdomains.qcn.github.io/

registrable domain = site

https://www.bunnifesto.dev:443/about/
Image showing a visual comparison between URLs from different domains, highlighting a "same-site" context with an arrow symbol.

registrable domain = site

https://www.bunnifesto.dev:443/about/ cross-site
https://qcn.github.io/secretpage.html same-site
http://why.so.many.subdomains.qcn.github.io/

Illustration showing examples of URLs with annotations for cross-site and same-site relationships.

same-site, same-origin

https://www.bunnifesto.dev:443/about/
site
origin
https://www.bunnifesto.dev/bun/ny.jpg
site
origin

same-site, cross-origin

site

origin

https://www.bunnifesto.dev:443/about/

https://bunnifesto.dev/talks/

https://www.bunnifesto.dev:1234/admin/

http://www.bunnifesto.dev/insecure.png

site vs origin

Visual comparison of same-site and cross-origin using example URLs with emphasis on differences in protocol and port.

Cross-site/cross-origin speculation?

  • Speculation rules prefetch:
    • same-site (same-origin or cross-origin): yes
    • cross-site: only if there are no existing cookies for the target
    • future plans: destination can opt into cross-site prefetches
  • Speculation rules prerender:
    • same-origin: yes
    • cross-origin, same-site: destination can opt in using Supports-Loading-Mode response header
    • cross-site: no

as always, consider what information you might be leaking!

do not rely (only) on speculation

it may be disabled for many reasons

out of all the scary things in this talk, this is the scariest
(as far as I’m concerned anyway)
The character Ralph from the Simpsons sitting in a bus seat with subtitles saying, "(chuckles) I'm in danger." The word "live Demo" is partially visible.
Screenshot of a web browser open to Google's homepage on the left and the Network tab of browser's developer tools on the right. Developer tools show a pending network request.
Image of the 'success baby' meme featuring a determined baby with clenched fist. Text reads 'Successful Live Demo' and 'Aspirational Slide'.

Thanks!

I’d love feedback!

I still like Vim (and light mode)
Image of the aurora borealis with vibrant red and green lights in the night sky. QR code with a small image of a plush shark in the center.
  • prefetch
  • prerender
  • DNS lookup
  • rel=dns-prefetch
  • rel=prefetch
  • fetch
  • rel=prerender
  • Speculation Rules API
  • link element
  • JSON
  • CSS selector
  • in-memory cache
  • Promises
  • async function
  • requestAnimationFrame
  • performance settings