Priority Hints with Patrick Meenan and Tim Kadlec

Watch the session

Pat Meenan joins to talk about the work he's being doing around Priority Hints in Chrome and how they're almost like a cheat-code for Largest Contentful Paint.Want more info?

Sign up for a FREE WebPageTest account and start testing

Follow Patrick Meenan, Tim Kadlec , and WebPageTest

Record on
This is some text inside of a div block.
This is some text inside of a div block.


Patrick Meenan
Web Performance
Google Chrome
Tim Kadlec​
Director of DevEx Engineering

Priority Hints with Patrick Meenan and Tim Kadlec

Event Description

Pat Meenan joins to talk about the work he's being doing around Priority Hints in Chrome and how they're almost like a cheat-code for Largest Contentful Paint.Want more info?

Sign up for a FREE WebPageTest account and start testing

Follow Patrick Meenan, Tim Kadlec , and WebPageTest


(01:28) Tim: Mr. Meenan.

(01:30) Pat: Well, hello.

(01:31) Tim: How's it going?

(01:33) Pat: It's going good. Exciting times. So lots of stuff going on.

(01:37) Tim: Yeah, no, I I've. I've gathered. I've gathered. Yeah. It seems like you've been, you've been busy over on the Chrome stuff lately.

(01:45) Pat: Yeah. I mean, its stuff that I've wanted to see ship for a while. unfortunately, I didn't actually do most of the work it's, [inaudible01:53] Dominic, a bunch of people on Chrome put in a lot of the effort a few years ago, even, with priority hints in particular. and it's just one of those things that I think there's enough value in it that I'm trying to like finally push it over the finish line and, with all of the core web vitals excitement over the last year or so, I think it's like the right time, because as we'll see, as we sort of chat about it today, it almost feels like priority hints is like a cheat code at least for the LCP. And it's like one line of change and you get 50% faster. It's like, not often you get that kind of win.

(02:33) Tim: No, it's not usually when it's usually when I hear that I get a little, like, I don't know. Jaded or bitter like what the board is, but like, I'm like, eh, is it really though? But like, no, I like, yeah,

(02:45) Pat: It's not gaming the metric either. Right. Which is what you usually get when it's one of those.

(02:50) Tim: True. True. Yeah. And thanks everybody for, for tuning into, as you can see, it's Pat was, is the person who built webpage tests and ran it out of your basement was webpage test headquarters for how many years? Like 12.

(03:11) Pat: Yeah, like 12 ish years. And you have no idea how liberating it was to get all of the infrastructure out of my basement. We could actually move, it's the things you don't think about that hold you back. Yeah.

(03:25) Tim: I'd be, I'd be fascinated to see the, well, I guess you moved, so it's like comparison is not apples to apples, but I'd be fascinated to see them before and after in terms of like the electric bill, but yeah. Cause there was literally just like racks and racks of stuff in your basement, which yeah.

(03:42) Pat: Not the greatest situation for production environment, but luckily we had reasonably, reliable power and internet and so it worked well, but I'm, I'm really excited that it's all running on, real production infrastructure with CloudFlare and real ops teams and people actually paying attention to it. I don't have to get up in the middle of the night and go, oh, it's down.

(04:09) Tim: No that's yeah, no, that's true. That's other people know, no, it is nice. It is nice to have it on the, like that whole system and the backing. And it's like a team working on its kind of fun, like yeah.

(04:22) Pat: And oh my God, the UI. Yeah. It's awesome to have you and Scott in particular working and cleaning up the, the old 1980s MySpace UI that I had for the longest time and pulled off a miracle, because you did a, a glorious sort of re-skinning without losing functionality. So it looks modern, but it it's actually even gaining functionality, which is like one of the hardest things to pull off.

(04:48) Tim: Well, and Scott's like Scott was the one who really did all the responsive work and like being able to maintain that the functionality and keep like responsive down to the, I think there was, I was thinking about it because there was a point cause I, I wrote a book about responsive design and then shortly after that I started working for myself and I was like, oh, I should like, and I was using webpage tests. I'm like, I should make webpage test responsive. I could do this. And I'm pretty positive. I pinged you about it. And you were like, go right ahead. And you were like, it would be great. And like you might even like set me up with like a separate branch or something. I don't remember. I just remember having the conversation and then being like, eh, once and it didn't happen. So it's nice to see that.

(05:25) Pat: Yeah. I think it was my usual go right ahead. Just don't remove any functionality. It's like, oh that's going to be hard on mobile, but yeah. I mean he pulled it off. That's pretty impressive. It's not only usable. It's actually really good on mobile now.

(05:38) Tim: Yeah, no he's pretty darn good at it. Yeah, it was turned out. Nice. Nice. It's good. So that is nice to be able to chat again. Like figured I already we knew at some point you were going to be joining a few of these, right? Like you weren't going to get out of here. So,

(05:55) Pat: I still use the tool like almost every day, so

(05:59) Tim: Well, and you're still contributing. I was going to, I joked I think it was maybe your first PR ever to the webpages project was once you were at Chrome. Right. Like it was,

(06:09) Pat: It's very weird. Not committing directly to trunk and having it roll out to production right away.  

(06:15) Tim: Yeah. No we try to be punctual sometimes we just let you wait for a little bit just to make it sweat, like make it interesting. But yeah.

(06:22) Pat: And it keeps production running.

(06:28) Tim: It's true that yes. Yeah. Nice. well, yeah, so like I told you before mentioned to folks and stuff like online, I kind of wanted the talk about like the priority hint, like so far, so far for all of these streams, we've either done like, just like very specific like live audit or, maybe show off a couple kind of features and stuff. This is a little different, this is like a new perf standard or emerging standard, I guess would be maybe the right word. What's the right word there? Yeah.

(06:58) Pat: That's probably the best way. It's definitely not a standard yet. It's yeah. It's in WICG as a proposal. And we're sort of working through the hoops to get it standardized enough where we can actually ship it. Right now it's under origin trial. So if you want to use priority hints and please use priority hints if it works well for you, under an origin trial and provide feedback, because that's part of what helps us finally get over that last hump and ship it without the origin trial. So everyone can use it

(07:31) Tim: Done. this the latest, and we'll talk a little bit more about the origin trial and all that stuff as we go. Is this the, the, the latest version of the WICG thing? Maybe the hold on.

(07:50) Pat: I was going to say, what's this, this you refer to,

(07:54) Tim: Oh, do you not see the banner? There's a banner.  

(07:56) Pat: Oh, there, yes. Sorry. Too many things to look at. Yes. That is the current version of it. And it really hasn't changed. I mean, the, I think 2018 is when it last went to origin trial, what has mostly changed is when it went to origin and trial in 2018, the focus was largely around JavaScript priorities. And so Chrome has a bunch of heuristics and there's a link to the actual table that shows under what situations different resources get, what different priorities and when they're going to load and stuff. and JavaScript was always sort of the more complicated one where blocking JavaScript, if it's render, blocking, like up towards the top of the document gets a really high priority if it's towards the end of the document, but still blocking, it gets a reasonably high priority, like a medium priority because the focus on the general heuristic across the web at the time was, that's blocking the browser from getting to Dom content loaded. If application logic's hooked up to Dom content loaded and waiting on the Dom, we want to make sure we get to that as soon as possible.  

And then async scripts and deferred scripts get a lower priority, because they're like not blocking the actual parser anywhere. And so, scripts in particular was, well, what if you have an async script that you want to run sooner? Like a lot of the frameworks react and all of that kind of stuff use a loader, that's all async and it's loading async scripts, but it's actually the core for the application and you want it to load quickly on. So the, the priority, hints was largely at the time around that there was, and the document has it there some focus on images, getting like carousels for the main image to load sooner and the other, images to load later. But it was mostly like, how do we load async scripts faster?  

Unfortunately at the time there was a, hack and it it's a complete hack and it's very 'em specific, but if you pre-load, a script, it gets the high priority of a blocking script, no matter if the script ends up being used async. And so everyone who cared about using scripts at a higher priority was already using the pre-load hack. And so priority hints, didn't offer any measurable benefit beyond the preload hack. I mean, it's a lot cleaner. You mark the scripts that you think are important as important, rather than having a link preload right in front of them. But there was no like metric differences or anything like that. And it was, if people had already made the tooling change, there wasn't a lot of reason. And so it, it kind of stalled out.  

We did didn't have good metrics that would've showed the benefits from like the images where, like I said, late body JavaScript gets kind of like a medium priority. Images always got a low priority until layout and they're discovered to be in the viewport and then it goes, Ooh, I really want these images now. And then they get boosted to a high priority. But there was no, no way to say load these images before the late body scripts, for example. And so, what we're trying to look at, and now that we have core web vitals in LCP in particular, we actually have good metrics that represent, sort of the, visual user experience where we think, the priority hints are actually going to be able to shine in a way that they couldn't, there is no hack.  

The only way to get an image to load quickly in Chrome right now is if you preload the image and it's like the first low priority resource, because even preloaded images are low priority right now. And Chrome will load one low priority resource at a time, when it's loading the critical render blocking stuff. So if you have an async script and you're preload for your images after the async script, your image is still going to get stuck behind the async script. But if you happen to have it as like the first thing, and you're restructuring the HTML and everything, you could technically get images to load quicker, but it's an awful lot of work. Sure.  

And so hopefully with priority Hints you just go, Hey, this is my hero image. Tag it and say, this is the important one. And then the preload scanner can see that well before render time. And it can go, Hey, this is a critical part of the, content, let me load it sooner. And interestingly that one low priority resource at a time during the render blocking phase actually came because of images. I think it was actually Steve Sauder's at the time when we were working on the resource prioritization in Chrome, he was working with Airbnb, I want to say, and they have that like massive background image on their page. And when we were delaying all of the images and only loading the critical render, blocking content, we would make Airbnb slower. For example, because, the text would load, but then the, the big hero image would load late and it was the first low priority resource in the page. And so we said, you know what, we'll do one at a time. And so we can hopefully get that, that one image loaded, in the early phase of Chrome's loading sequence.

Pages have been restructured since then. And even on Airbnb, the hero image is no longer the first image in the markup. And so we're loading an image. It's not necessarily the important image first, and then we'll load three or four images on Airbnb before we get to their actual hero image. and so this hopefully gives devs a way, in markup, to tell the browser, Hey, this is the one that I want you to load or this, I need you to load sooner, in ways that they couldn't do it before it is specific, the Chrome, I mean, all browsers have their own prioritization engines internally. And hopefully they'll adopt it. And they all have reasons where boosting the priority will still improve their performance.

Usually it it's boils down to HTP two or HTP, three prioritization where they'll pass the priorities down through, to the origin, or even in the case of HTTP one where you have like six connections, per origin, which request you send next is, picked based on priorities. And so even for non-Chrome browsers, when they adopt it, you'll still get some head of line jumping. It's just, most of them don't have the sort of two phase loading that Chrome does where it's mostly only the render blocking resources, right at the beginning of the waterfall and then everything else. And for Chrome, the big knob that you can turn is moving things across that line. Things that would normally be loaded late in the waterfall. And I can, if you want to share,

(14:34) Tim: I was going to say let's yeah. Can wen that's one of the questions is like, if you're like, I mean, first we'll have to go through like how you add the priority and stuff like that and what that looks like. But one of the questions was like, how do you even know that this is going to be something that potentially is worth looking at

(14:53) Pat: Yeah. So, in this case, it's Amazon, but it's sort of the, the stereotypical waterfall for, both what looks like a priority, hint opportunity and also sort of crumbs two phase loading. And you sort of see you get the HTML and then you have this long, sequence of CSS and stuff that's loaded, in parallel. And then there's kind of a little break and then everything else, and this is sort of the, this is the render blocking head content, phase when Chrome is loading, it knows about these other resources, but it hasn't, there's like no light bar or anything. It hasn't actually issued them, even internally to chrome, until it gets past, reaching the body tag effectively. And then it opens up the flood gates and requests, all of the images.

And so this is kind of the stereotypical and actually my favorite view these days in webpage test is yours. Tim, it's the, I jump straight into the web vitals view. Because I really love the well first seeing yes, it is an image, that is the core web vital LCP element and it's in the HTML markup. And so that's one thing that tells me, Hey, this could be an easy candidate for priority hints because it's in the markup, it's an image and it's load in this sort of second phase of the waterfall. And I like, it's really nice to be able to look at the trimmed waterfall with the highlighted element. You can go, okay, here, I can see the HTML parse happened here, like right around one and a half, 1.6 seconds. And that's when it actually would've discovered the image and most of the other content, but it didn't request it until two and a half seconds.

And this feels like one of those, hey, if I just put an important equals high on the hero image, it's not the first image that's loading. It's not the first low priority thing that's loading. But you can sort of predict that go, okay, this image can load at the same time as all of these other things, it's still on a different origin, unfortunately. It’d be nice if they could coalesce those connections, but big companies have reasons. And so at best you could move this image to load here, like at one, 2.1 second, give or take.  

(17:12) Tim: So right after the connection

(17:15) Pat: Yeah, right after the connection is established and you can get it loading at the same time as the CSS and stuff. And so you could predict that instead of finishing the image loaded around 2.8 seconds, you could probably finish the image loaded around 2.4 seconds. And so shave likely 400 ish milliseconds off of LCP or getting that image loaded. And you could actually have the initial render because the first Render is right here at the 2.7 second mark or so, and right now it does like the initial render, first contentful and then the largest content full kind of one after the other. If you have the image already ready by the time it does the first paint, the initial paint of the content could actually have that hero image as well. And so let me see if I actually have yeah. And so, we'll get to how I did this in a second, but so when we add the, a priority hint, to let me drop it to a more granular, also very cool that all of those radio buttons are now inside of a simple settings area.

So now the initial, content display is, maybe a hundred milliseconds later, than before, but it includes the product image and everything else. And it's a huge win on getting the product image there where in this case it loaded at 2.9 seconds, whereas previously 3.8 seconds. So almost a one second savings for like one of the fastest websites in the world, for getting the main product image loaded. I can't make the call, for Amazon one of the, one of the things that does change is like here, the stars, for the reviews for the product loaded at the same time as the image and now the stars don't load until after the image does that matter for conversion engagement, all of that kind of stuff I can't really speak to. But as far as being able to control when things load and how quickly they load adding importance equals high to the product image was a 30% win, to the metric right off the bat. And it's certainly worth experimenting with.

(19:29) Tim: Can you jump into the waterfall on that one and show like the waterfall difference there too, just so everybody can kind of see where, cause I know you described the shift, right. But the shift happened.

(19:37) Pat: Yeah. And so here you can see, yes, there's nothing before and it loaded. Right. And there's the importance equals high now on the, the image element and here we have it, it's issued to the browser as soon as it's parsed in the HTML. And as soon as the connection is available, it goes out over the HTP 2 connection and it loads, however, the connection sequences it relative to the CSS, but in parallel right after. And so, yeah, its right before the initial render, the image is already there, so it can get painted right away. And it's usually right at the beginning part of the waterfall, the bandwidth isn't, this is another really nice thing to sort of look at when you're looking at the web vitals version of the waterfall is the bandwidth utilization. Usually it's not saturated right at the beginning part of the waterfall.

And it's really not saturated at that transition point between the render blocking content and the rest of the content. And so it really does usually come as a free win where you can move it earlier and it kind of gets sequenced after the render blocking stuff, but before it normally would have loaded. So like here, you see it's at the end of all of the CSS, which is even higher priority. But it's still before it would've normally been loaded. And so you get kind of the free wind by kind of stuffing it into that free space in the waterfall as well.

(21:05) Tim: So is there less risk because you said you, so we know there was a little bit less work like for using preload. Like now that preload has been fixed, which by the way, if you haven't, if you have preload in place, what version of is that version 95?

(21:21) Pat: 95, I think. Yep.

(21:23) Tim: Yeah. So if you were using preload, and you haven't looked since like Absolut lead compare, like what happened in version 95 and 96 for performance because the entire behavior of preload changed, like it was a bit of a blunt object, thumb instrument, I guess that kind of just shoved something like super high priority. And now it tries to keep like some sense, like you said, a source order and stuff like that. So could we achieve, we could achieve this by using preload, but then we'd have to be pretty particular about where we put preload in the page. Right,

(21:53) Pat: Right. And so, well there's two parts to it. You could've mostly achieved the same behavior by putting the image preload as the first low priority resource that the parser sees anywhere in the document. Right. And so you would've had the pre low tag up in the head before any async script. And before, however, these low priority JavaScript, or medium priority, style sheets are added, maybe non-media matching or something like that. But, yeah. So if you structured the HTML just right, and you inserted the, the preload tag at the right point, you could have got the browser to load it sooner. And that's why it's not like if you've already done that with your HTML, you may not see a benefit to using the preload or if you, if you’re HTML consists of one image and nothing else the priority, hints may not show any benefit above what you're already.

What you do get is when you use the priority, hint on this is no longer a low priority image loading. Soon. It is now a high priority image. And so the one low at a time still continues. And so whatever was loading, you didn't like remove what was loading originally. And you're not using that one low priority slot at a time. You've literally just moved the image into the other bucket without removing something else out.

(23:20) Tim: Got you.

(23:21) Pat: And so there, there is even the priority, hint above preload does have a slight different, change in behavior, but not having to change the markup and structure it exactly right. Sometimes, especially with, frameworks and CMS, it's a whole lot easier to go, just emit the importance equals high tag and be done with it. I will say, just like with lazy load don't tag everything. I

(23:47) Tim: Rick posted this question in the chat hybrid, by the way. Yeah. Prioritizing everything elevating the priority of everything is probably a bad idea.

(23:57) Pat: And yeah, I mean, you don't necessarily want to just, prioritize your hero image, for LCP, if you have an LCP hero image and you want to improve your LCP, that's the easiest way is to just prioritize the hero image. But if you have, like a logo and other images that make up the actual, Chrome of your page, for example that's in the viewport that you want to see soon, by all means, add importance equals high to those as well, because they are important. And once layout happens, the browser would naturally have, boosted the priority of those. But if you can give it a hint earlier, you'll get more of your UI on the screen sooner. If you tag it, but certainly the hero image, the main product image, that kind of thing is kind of a no brainer.

But yeah, if you slap it on all of your images, you'll probably turn Chrome into safari and where everything loads all at the same time, and then it's going to be up to the network or your servers to sort out priorities and what gets served in what order. So be careful, you can't damage anything. If you boost the priority, worst thing you'll do is you'll accidentally make it a little bit slower. So watch your metrics, you won't break anything. The order things get loaded in is really just an optimization for how quickly things can get displayed. It won't change the execution unless you have timing bugs. But yeah, so be judicious with it, I think is probably the best way to put it.

(25:31) Tim: Good advice. Probably good advice with most things like this. Yeah. Okay.

(25:37) Pat: And so I guess it's a good time to jump into the how right. Yeah. And so like I don't own Amazon, unfortunately. And so I also don't have commit rights for some reason. They don't give me commit rights to their production pages. And so I couldn't actually go in and do the importance high on the production Amazon page. And so, CloudFlare workers is sort of my go-to, it's incredibly useful for prototyping this kind of stuff, particularly combined with webpage test. And so let me see if I have, yeah. So webpage test scripting language has a really zoom in on that. Has a, a really cool feature called override host, where you can. And so there's a substitution pattern in this case percent host is just whatever host I happen to use for the Earl on testing. And so in this case, it would be

And what it does is, is it says any requests going to instead sent to, but do it under the covers. So the browser cores, everything else still thinks it's talking to we’re just rewriting the network requests to go to a different destination. And it adds an ex host header, to the requests to say, okay, I know I'm requesting, but this request was originally for dub And so whatever's on the, the server side can go, Hey, okay, I got this request. This is the URL fragment, but I really wanted it from And the second part just says navigate to whatever page was being tested. And so you can test any page on any site and rewrite it to go it through this is my CloudFlare worker. I think I was fairly early in the workers.  So I got as my origin from their free, workers. And so it's the great thing about a lot of things CloudFlare. You can sign up for a free worker's origin and set your own worker up and do all of this prototyping without actually having set up a full CloudFlare account or anything.  

Although I do recommend workers are just awesome for all sorts of reasons. Like if you actually have a production site going through CloudFlare, you could actually use these workers to insert your priority hints for reels and not just for testing. And so on the cloud flare side of things, Andy Davies, Matt Hobbs. Props Matt hope you're feeling well, glad to see you're here. But, they have articles, really good articles on how to use, CloudFlare workers combined with webpage test, for prototyping.

And so this is mostly based on Andy's, worker and there's some boiler plate at the beginning. The basics is, this is the main entry point into the worker. let me zoom in just a little more where it's basically just anything that comes in, run this, respond or run this handle request, function and pass it back to the requesting browser. And this one, it basically looks at the URL that came in for the request. And it looks to see, is there an ex-host header added from webpage test? If there isn't an ex-host header, the request probably didn't come from webpage test using the override host fail it return access denied. So you don't end up running an open proxy for the web kind of thing through workers. But if it does have the ex-host basically just replace the URL host with the host that came in the ex-host header. So in this case, it would, replace the part of the URL with and keep the rest. So we have the, the full path to the product page and everything else.  

This bypass transform I wasn't using at the time. And actually you don't need to use it right now anyway, because, priority hints is on origin trial. But you can add this header to your webpage test to say, even though I overrode the host and I'm going through workers, I want the worker to do nothing with the request. So you get a good AB because you don't want to test Amazon production, page, and a proxy version of the page against each other, because they're going to be on different infrastructure. And so you can proxy both the before and after, and just turn on your rewrites for one form of it. If you pass this header, it'll turn off the rewriting and just pass the request through so you get a better AB comparison. then the other thing it does, and this is specific if you're rewriting the HTML, if you want to like, rewrite everything, you can remove this filter, but this is basically just looking, does the request have an accept of text HTML? Is it an HTML request? Everything else just gets passed through as a straight proxy.

But if it is an HTML request and we're not bypassing the transforms, We fetch the origin request and then this HTML rewriter is kind of a really cool, so I'd say probably two years ago when I was actually at CloudFlare didn't exist yet. And so you had to fetch the text rejects the test text and mark it up. But now there's, a streaming HTML rewriter that will stream the response as it's coming through. So there's almost no overhead and you can

Selector queries, against the HTML to say, Hey, when you get this match on the selector, run this function, against the request and then transform the response as it's going through. And so what I did was

(31:37) Tim: You've been it looks like

(31:38) Pat: Yeah, yeah. Say these are basically all of the tests, all of the pages that I've tested, and prototyped using workers, the ones that didn't work, I probably deleted. So I think I actually tried more than these. These are mostly the ones that worked, I don't think I blogged about, but the reason I didn't blog about that one was it was using both lazy load and a hero image. It was using lazy load on the hero image and my worker. So if you look at this prioritize high function, all it does is it takes the element that was, matched in the media query or in the selector. And it removes the loading attribute and it adds the importance equals high attribute. And so it felt a little like cheating to strip the lazy load off of as part of adding priority hints. But it got a lot faster obviously.

But the rest of them, Google flights, best buy Amazon, Amazon, they all I'd say probably the hardest part of all of the work was getting a selector query that would match just the hero image, and not, a whole bunch of 'em. So like this Airbnb was awesome. FMP target first meaningful paint. And so they've got like the hero image already tagged with a nice ID, that you can go, hey, this is their hero element. Yeah, I say Fox news is probably the most complicated path. I think I still hand created that one. I don't think I copied any of the paths directly out of like dev tools, copy selector path or whatever. Sure. Because I wanted them to be a little more robust to pace changes.

But once you have the selectors, really all it is doing is adding the attribute importance equals high to the, markup at, as it goes through. And so when you do that, combined with the script, for priority hints the only other thing that was actually needed was a command line flag. Let me see if I have, yep. So, the enable blink features priority hints, command line flag. So in the chromium tab of the advanced settings, you can just pass the enabled blink features, priority hints. If you're doing it on production site right now, you'd actually be using, an or origin trial token. But you can turn it on from command line just by doing this. And so when I was doing my AB testing, I wasn't using the host header to turn off priority, hint support, because I was letting, it rewrite everything anyway and add the importance equals high. I just wouldn't pass this command line flag to Chrome. And so priority hints wouldn't be enabled in the before and with the command line flag, it would be enabled in after, but both would get the full rewrite.

Ooh. So that was a fairly big mouthful and yeah. So Matt's got in the comments, a plug to his, blog post. I highly recommend reading it. Yeah.

(34:55) Tim: Yeah it’s rock solid stuff.

(34:58) Pat: And so I guess there's also a question about how to inject JavaScript to an existing HTML response. I recommend looking at the docs for workers. You can, match on like the end of a body tag and insert a script element and you can insert sort of arbitrary things. No JS doesn't really come into play. But you can then inject arbitrary script, you can rewrite any page elements. It's pretty freakishly, capable. And I haven't tried it with the Fastly, edge.

(35:32) Tim: No, I haven't either. I see that question about the I played a little bit actually with the Fastly edge a little bit, but for that I know there is a really good, like there's a blog post out from Fastly. Like they talked about using the computer edge to prototype speed optimizations in webpage tests. So, if you are a Fastly user, that's something to dig into there.

(36:00) Pat: I see Barry's commenting on my English.

(36:04) Tim: I was not sure if I was going to call you out on this one or let that one sit. I was going to let it sit, but yeah, no, it's the Earl you’re testing. Yeah. Yes.

(36:17) Pat: Do I have to potatoes and tomatoes too or aluminum? The aluminum Earls? Yeah. And so like with Google flights, for example, we were looking for, it's one of those things when you work for a large company, and you create blog posts, you can't use other people's content. And so it like, okay, let's find a Google property that we can use priority hints on that will show the benefit. It turns out there's a crazy number of Google properties that don't have any images. And the few that did have images, it's like, there's nothing but like one image on the page. And it's, so flights ended up being a fairly good one where it's got this hero image, it's got a whole bunch of other stuff. And the hero image is the LCP element. Let me see. Yeah. I don't think I have just the test result. And so it was one of those, go ahead just inspect it. Start playing with the path to it. I don't, let me see if I can see what did I actually end up using as the-- Google flights? Oh, okay. The class. Yeah. That doesn't feel like it's terribly robust considering it's like a generated class.

(37:35) Tim: Yeah. That class thing makes me a little nervous about the robustness of it, but yeah.

(37:40) Pat: Yeah. But when you're prototyping and you're hoping to run a test against something that hasn't been built and changed. Yeah, it works. But yeah, the actual selector from Chrome would be, Pretty-- So I would do query selector all I think. And then just yeah, so that, that would like be the query selector from, dev tools, which would work. It feels a little more, Breaky than the one that I used. and so I tried to be a little, and so when I'm playing with it, I basically just sit in console and do query selector all and then try a bunch of different query selectors until I only get the one element back, instead of 20 or 30, when I'm prototyping it against a site. If you actually own the site, you have a lot more control over doing that. And so like with Google flights, when we did it, it actually ended up being, let me see if we can go to a hundred milliseconds as well.

So I'd love to talk to the team about getting this actually rolled it to production, but yeah, so the main hero image and content loaded, actually in this case, even sooner than it would've loaded before. But the LCP fired, what are we here? Two seconds versus way out here at 2.7 seconds. And so a 700 millisecond win on a three second page is a fairly huge win. It’s a fairly simple page. The one I think I was more so I was really excited about the Amazon one, for example, just because it's already so well optimized, that being able to get that kind of a gain, maybe I over zoomed, being able to get that kind of gain on a product. And so this ends up working for, almost any e-tailer. I will say it gets a little complicated if you're using something like react or a spa framework. That’s not doing server side rendering.  

(39:52) Tim: Sure.  

(39:52) Pat: There's not a lot priority. Hence can do if your JavaScript is sort of the building, the UI and the, the slow point. And if it's already done layout, you might be able to get a slight bit of a win if your, SPA can still tag the hero images as important. But your long path, is going to be the framework. So it works best if you've got something emitting, HTML, whether it's SSR or just a straight old HTML, classic content. But it works really well for e-commerce, for getting the product image loaded.

(40:31) Tim:  that's kind of the parf of the course, right? Like if you're using a JavaScript framework, like for an S SP architecture, like it's just interesting, because it is like to switch, right? Like if you're using an SPA, then you're probably going to spend most of your performance optimization time in the JavaScript. Like that's where the bulk of your work's going to be. And like mechanisms like this become more interesting if you're not using that SPA. Because then if the JavaScript kind of yeah,

(40:55) Pat: Yeah. And so like Etsy, another product page that we love well, because Etsy has an awesome performance team. Yes they do. Same deal, the product image can load in this case, what is it? 3 seconds instead of, fully loaded here at 3.6 seconds. And so that's still a fairly significant win. And it doesn't look like it like degraded anything else, you still get the rest of the UI loading even a little faster, without sort of penalizing anything else. Let’s see what else we've got, ah, shout out to Lynn's cards.

Yeah, so, it's sort of a MySpace looking page, but it has a massive background image. Thanks Lucas from CloudFlare for suggesting it. But yeah, even that with as complicated as it is, we could still boost the priority of the background, image, it wasn't really a background on image. It's a placed image, and still get a one and a half second win on getting that main, it sort of surrounds the video if you would, getting that loaded. I will say if you've got a background image, that's your, LCP element. You can still use priority hints to boost it, but you need a preload tag, to actually put something in markup that the browser can see to load the image. So you'll both be, pre-loading the image, that's your background image and also adding an importance equals high to the pre-load tag. And that's what you do if you're using a background image.  

Cool thing is I didn't real realize this until, [inaudible42:38] told me that the preload tag takes CSS media queries. And so if you're using, responsive design and you don't have a hero image in mobile, but you do have a hero image in desktop, or the background image changes, that kind of thing. You can use your same media queries with your preload tags for image and put the priority, hint on that on the preload tag, if you want to boost the priority of an image only for desktop or only for mobile, you don't have to sort of make the call and always,

Ah, so ignore the actual content. So for, it's not just e-commerce right. Its content sites tend to have a big hero image for the main story element, for example. And so my first gut reaction was to try CNN. I gave up fairly quickly. It looks like it's mostly a fairly complicated react app these days. And so there wasn't an easy way to rewrite it. But Fox news ends up being a fairly straightforward HTML-ish, piece of content. And we've got sort of the, the hero image. And since it loads late and the space wasn't reserved, it also causes a layout shift. But when we look at the waterfall, it's got sort of that typical pattern where you've got like all of this critical render, blocking stuff, loading, and then all of the images load and the hero image is one of those things that loads fairly late in the general waterfall cycle if you would.

And there's some other, static, logos and stuff that happen to come before it, in the markup, even if it's not things that are sort of front and center for the user. And so rewriting it, adding the priority hint, we could get it. This is the waterfall. So before it came out at request number 25, and there was a whole lot of other stuff coming in before it is still on a different origin. So the connection still needs to be established, but once we boosted the priority of the hero image, it actually ended up loading as request number four. Most of the other stuff. Oh, highest. So it's probably just a factor of how quick the connections actually got established, that it ended up loading even before the CSS and stuff. But it loaded well before the initial render. And that's how we got such a huge jump in the performance, to where yeah. Previously you'd get like the text content 2.8 ish seconds. And then you didn't actually see the hero image until 3.3 seconds. And it shifted the content down. And with the priority hints, the hero image was already in place by the time the initial render hit.

(45:18) Tim: Also in this case, we actually get a little CLS boost too.

(45:20) Pat: Yep.  

(45:25) Tim: [Inaudible] with a height, width attribute or something like

(45:27) Pat: You probably still want the height and width attributes. So you're not relying on the image being loaded sooner, but it's nice that your initial pop of content actually has your hero image in place.

(45:42) Tim: You kind of alluded to it maybe, but there was a couple of times now I think Matt asked and, Brian started this with like priority and we're talking a lot about like raising priority. Right. But like priority hints and preloads together. Like you could.

(45:55) Pat: Yeah. They actually work really well together. So like I said, with scripts in particular, if you preload a script, it's going to default to high priority, as if it was a render blocking script. Now it's possible that you have async scripts that you want to pre-load because they're like dependent modules for another async script that you're running. But you don't want to pre-load them until after the parser has seen the other async script, but you also don't want them to load at a higher priority than everything else. You can lower the priority of the async script that you're pre-loading, blocking scripts at the end of the body is a big one where they're like sort of a medium priority by default. If you want to lower them to be the same priority as images and load in parser order, instead you can lower the priority of them.

I saw the question actually called out fonts specifically. You can lower the priority of preloaded fonts. The default priority for preloaded fonts is already lower than, regular font priority. So it's not like super high priority, but they are still loaded at a relatively high priority. If you preload them now and so you can lower it even more. But that's part of what got fixed as part of the 95 pre-load fix. Whereas if you are pre-loading fonts before they would load before everything else, just because of the pre-load hammer. Now, if you pre-load fonts and you have your pre-loads like at the end of your head, they will actually pre-load after your scripts and everything in else that were loaded before it. And so you have a little more granular control even without priority, hints right now on fonts. But yeah, the easiest win is boosting image priority. But yeah, you can lower, script priority. You can make it more deterministic about sort of make things load in parser order if you want to, rather and boosting things out of order.

(47:49) Tim: Interesting. You also alluded to this one, I think, with the developers.Google site. Right. But like, because I think your worker script that you showed, you're actually pulling the loading attribute on entirely right away just to make sure it's not like lurking about right. Because these are going to be conflicting. What if you had, if you were loading lazy on a script or on an image should say and you give it an importance high would it just self-destruct?

(48:16) Pat: No. I mean it won't help much. so I think of loading equals lazy, loading equals more as a, when does the browser decide it wants to load this resource and loading equals lazy means it won't decide to load it until it knows it's close to the view port. Regardless of what priority it chooses to use when it finally decides to load it. And then the priority hints is more about when the browser has decided it wants to load something. How in important, should it be, relative to other resources that it's thinking of loading at the same time. And so they don't conflict with each other. I don't know that you'd ever want to use both at the same time. If you're using lazy load and priority importance equals high. In theory, if an image is already in the viewport, it would've been given a high priority by the time lazy load started anyway. Because Chrome Treats

(49:22) Tim: Forgot the do not disturb there.

(49:27) Pat: Yeah. So Chrome treats in viewport images, a high priority that said, below the fold images will still load, with loading equals lazy. Just because of the near viewport, it wants to have them loaded by the time you scroll into it. And if you use importance equals high, those will load at a, higher priority than they would naturally. So they don't really conflict with each other, but there's not a lot of reason to use them both at the same time. I will say the one thing I didn't call out. And, I know of a few cases where they're going to be important is, it's not just an HTML attribute. It's also, a parameter to fetch. And so on the request for fetch, you can say importance equals high or important equals low. And so for your API calls, you can prioritize them.

And so if you've got a bunch of API calls that are loading background data, for example, some JSON that you need for some weird purposes or whatever, and you also have like type down auto, complete API calls as someone's typing in a search bar or something like that, you can prioritize the user interaction, API calls as high and the other API calls as low. And assuming you have a server that will honor priorities on HTP 2 or HTP 3, you can actually interrupt the streams, and get proper prioritization and more responsive user input, by controlling the API as well.

(50:56) Tim: Okay.

(50:56) Pat: And I did want to, the last one I did have was Airbnb, since that was the, the, the one sort of the stereotypical case and yeah, by actually adding importance equals high to their, their hero image. We're back to the point where we shaved another 600 milliseconds off and got the main hero image loaded a lot sooner. Like it was originally intended to be able to do. But without relying on browser heuristics to do it now, the site can actually say load this piece of content sooner.

(51:27) Tim: Nice. Yeah. It's pretty clever stuff. And like, so I think, yeah, I think what, yeah, you started this off by saying it sort of, what did you say to get out of jail free--

(51:39) Pat: A cheat code for, for LCP.

(51:41) Tim: Yeah. Which, sure seems to, it's one of those here's examples, at least where at least when it was judicially implied like carefully, like cherry pick the LCP engine, don't just go nuts and start tweaking importance of everything. Like there was very little, if any downside to any one of these examples here and the impact is it's sizable, like you said, the Amazon one being a really good example. Amazon does so much work to optimize their pages. Like they're kind of like, one of the poster channels for that kind of thing. And like to see that big of an improvement there is.

(52:19) Pat: Yeah. And I mean, even Google flights too, it's like, sure, yeah, Google flights aren't known to be slow, but it just wasn't something that you could actually control. Before, and so, I mean, for a lot of people that actually have OKRs or goals around improving performance, you might be able to reach your goals with one quick change and take the rest of the quarter off

(52:40) Tim: That's that'd be pretty quiet. Well, there you go. That's pretty awesome. More time off. Good for that. Rick's question I thought was interesting because it's funky. When the LCP for a given viewport depends on the initial scroll position. So let's say that you have a page with those deep links to anchors or, subsections of the page. And presumably those, direct links are getting enough traffic to warrant you caring significantly about like what you're going to do for your LCP. Because what's in the content of that NFL viewport's going to be different. Your LCP is going to be different. I honestly am not sure what my advice is here. Other than like first off, like the first thing I'd say is like, make sure you're actually getting significant enough traffic to [inaudible53:23]spending time figuring this out anyway. But, and

(53:26) Pat: I was going to say, I don't know that there's much that you can do because usually those deep links are fragments. Right. And so they're not visible from the server. And so when you're generating the HTML, you don't have the visibility into the fragment or where you are in the page or what it's going to auto scroll to. Yeah. So if you do have a lot of deep links that are happening, I don't know that there's much you can do.

(53:59) Tim: Yeah. That is kind my conclusion.

(54:00) Pat: And it’s going to be the same problem for lazy load too, right?

(54:04) Tim: Yeah. Yeah. Matt requested that you blog about all your priority information, which I would just like to put it out there that, I know, you can contribute to, whateves but like would also accept such posts and content, but it would what I, but this, I guess the thing is like with prior hint and with the change in preload, respecting kind of source order and not just boosting things up to a super high, like front of the line kind of queue, it does feel like knowledge and understanding of the prioritization process in Chrome is becoming like increasingly important for optimizing in that browser

(54:50) Pat: Probably. And I will say there's the one Google doc that's linked from a bunch of Addie's web dev articles. And I think from the priority hints article as well, which has what the different priorities are, for the different content types and it a section down at the bottom of the doc as well, that has when priority hints are applied, this is what it does to the different, types of content as well. That's probably very important.  

I will say prioritization is a fairly big problem in general and there's things that I probably haven't talked about and aren't in the article, some of the things like when Chrome, so browsers in general, go through the HTML as it comes in and as they discover things, they do something with those things. And so for Chrome, for example, it won't hold back low priority resources, unless it actually has high priority resources. And so in the beginning of your HTML, if you have a bunch of image preloads for example, like 10 image preloads and then you have a script tag, the parser is seeing those 10 image preloads well, let's call 'em.  

It might not be the best way but let's say you've got 10 medium priority blocking scripts and then one CSS and one font or something like that. you would, if you look at it holistically and you look at the prioritization, doc, you'd go, okay, the CSS should go first, because it has the highest priority, but you have to kind of think of it in the terms of the browser parser and the preload scanner, where it sees the HTML as it's coming in and it goes, okay, this is a medium priority resource let it through. It goes out right away as a request. And so even though they're not in priority order, you'll tend to see like the beginning of the waterfall will actually show up in parser order.  

Like as the browser discovers stuff, it requests it and it passes it straight through to the connection until it actually reaches a point where it has back pressure on making requests. And then prioritization starts to come in to what it chooses to send the request out for. But like the high priority CSS, versus JavaScript, it will still at a connection level pass the priority through to the origin. But it will be in whatever order it came in. one of the things that I have on my list to play with Chrome in particular is to, delay a little bit. And so as the browser sees, like if it gets 10K of HTML, all in one chunk, instead of processing it one token at a time and then sending the requests as they come through, process the 10K collect all requests that would've been sent. And then when we're done with the 10 K sent things out in priority order. Don’t know if that's going to be a win or not. Because there's something to be said for the early stuff actually going in part order.  

When you start talking about like prioritization across connections, coalescing HTP, 2 connections, whether servers actually honor priorities at a connection level, for a long time, Chrome would for HTP 2, it would not do any local browser prioritization. It would just send everything through to the origins and let them sort it out. But given how many third parties are on pages and stuff, it ended up being that. Yeah. I mean, we'd send all the requests out, but they're across five different connections and they're not actually prioritized against each other. So Chrome reimplemented, the HTP1 style throttling, where you sort of get the two stage waterfall, even for HTP 2, because of that, which feels like a shame. Another thing on my list to try and do is to see, can we at least do it like for same origin and things like that, but yeah, there's a lot of subtlety in the prioritization logic in general.

(59:01) Tim: So, this is a question from Matt. I want to make sure this brought up, cause this is kind of part of the reason why we wanted, I wanted to bring you on for this anyway, like we talked at the beginning about how this isn't really a standard yet. It's like a Chrome thing in origin trials. It's an emerging standard if you want to call it that. What's the process for this specifically and just kind of in general for like, how does this get to a point where it actually lands?

(59:29) Pat: So the, the big blocker is getting developer feedback from the origin trial that yes, it works. Yes, we want it. And yes, the API surface the HTML attribute. The fetch parameter, is easy to work with and doesn't need to be refined. Like one of the things that we're sort of debating on the issue list for the, the WICG spec for it is, would it make sense to combine it with loading? So you have loading equal urgent loading equals idle and loading equals lazy. It’s tough because like loading equals eager right now, which is more important, eager or urgent. How do they interact with each other? Does it make sense to have separate attributes? then we need to in parallel, send it for tag review, which is just sort of the architecture group for W3C C for them to weigh in and go, yeah, those attributes look yeah, reasonably good. Go ahead. Feel free to ship it.

Request feedback from other browsers. It's not a blocking, issue of any kind, but just check in with, Mozilla and safari WebKit to see if they have any concerns about the API surface. They all use prioritization. So in early feedback I've had with them, they're interested in seeing how it plays out. They're not actively working on it. But the big blocker for Chrome actually shipping it is to get feedback from devs. That it's a valuable thing to have. So we're not polluting the attribute name space unnecessarily. And so, yes, please try the origin trial and more importantly, provide feedback, send blog posts, do whatever about the benefits you got. And I assume most sites that it would matter on are in, a moratorium of some kind, but next week is black Friday. So if you have an e-commerce site and you want an easy win for your performance metrics, before that, here we go.

(1:01:35) Tim: There you go. Yeah. How do they get to the origin trials? How do you register for one of those?

(1:01:39) Pat: Yeah. So if you search for origin trials for Chrome, I think on our, our blog post, we also have a direct link to it. But there's a list of currently running origin trials, just click on priority, hints and register. And what you do is you give it a domain, like www or whatever, and say, I want a token for this domain and there's no review process or anything. You'll get a token back. The one you do say, do you want all sub domains? So you could do like, which would cover like any static domains under that as well. And then it is important. The token that you get back needs to be sent in the HTTP headers, there are two ways to do origin trials. You can do it in markup with a Meta HTP equiv tag or in headers.

This origin trial impacts the preload scanner. So it happens before the HTML is parsed. So you can't use the origin trial token in HTML it won't work. You can put it there, it just won't do anything. And the other thing they ask you is like, how many page loads are you expecting to see, that's not a gate to anything, but if you're running a site like the size of Amazon, you can't actually ship it to production a 100%. I think the origin trial automatically turns itself off when it gets to like 0.5% of usage across all Chrome page loads. And so if you're running a really massive site, you need to do it as part of an AB test or an experiment to a limited select group of your users, just so that you don't cross that threshold and kill the origin trial for everyone.  

(1:03:20) Tim: I was going to say the origin trial, I'm guessing the reason why they cut it off is a safety mechanism in case things are bad,

(1:03:26) Pat: Right, so the reason origin trials were created was we didn't want to pollute the, the HTML name space with prefixed, like web kit dash, features. And so they want to keep usage of the deprecation threshold, which means we can turn features off without, having to notify everybody. And so if it got too wide usage, it would become a defacto standard without actually becoming standardized. And we want to avoid shipping something until we've actually nailed down the API surface and what it should look like. And we could get stuck into a situation where we can't change the API because 30% of the web depends on it as we shipped it when we were testing it and now we can't change it. And so that's kind of why they want to keep the usage down, but still get enough feedback. And there aren't a lot of sites that can move 0.5% of overall web usage, but there are some right. And so just have to be kind of careful in there. To be fair, those sites that can move that kind of traffic wouldn't ship it to production without doing a trial anyway. So anyway, so it fits in pretty well.

(1:04:32) Tim: Yeah. Those aren't the kind of sites that are just going to roll that out to mass. Yeah. A hundred percent of the audience. Nice. Yeah. Okay. Well, I mean, we do have, do you have a couple minutes? There's like one or two couple questions that have been to kind of trickling in.  

(1:04:49) Pat: Yeah, Happy to.

(1:04:50) Tim: So, this is not necessarily just priority hints, but we have been talking about LCP a lot as it relates to this. Just a question about, LCP element, how long is it looking for that and all that kind of jazz?

(1:05:05) Pat: Yep. So webpagetest will look for an LCP element into the end of the test. And so if the test ends before the consent banner shows up or whatever else, webpagetest won't capture it, Chrome itself looks for the LCP element until the first user interaction. I don't think scroll counts as an interaction. I can't remember.  

(1:05:26) Tim: I don't think so either [Inaudible] Interaction right. And then scroll is considered passive. So usually scroll is kind of excluded from those categories.

(1:05:32) Pat: And so the entire session up until the user actually does something with the page, for Chrome, will get looked at. And so if you have a slow loading consent banner, but it does show up for the user before they exit out or click on an article or something that will get marked as the LCP element in the field, and search console and everything else. That said, it can go both ways because if you have a consent banner, that's cookie based and they accept it, repeat views won't have that as the LCP element anymore. Right? So because Chrome is a RUM measurement, it will report the LCP of whatever they're looking at. And so if they come back and they've already accepted the cookie banner, they will won't see it. And so you may end up actually having bimodal, tri-modal, LCP elements in the wild

(1:06:24) Tim: Makes sense. Okay. I did find the doc, and then, dropped the link to that in the chat. But then Matt was curious if that was up to date. Apparently it's got a 2015, I'm going to see if I can pull it off really quick again, date on it. But I think you updated that one pretty recently. The prioritization stuff.

(1:06:46) Pat: Yeah. I don't think there's been more than one doc. I mean, it has a created, but it should have a last edited. Yeah. Sorry. Yep. If you, yeah. Got the way down at the bottom, it's got the priority hints table. Yes. That is the authoritative doc. it was originally created in 2015, but it has been updated over the years. There haven't been as many changes as you might like since 2015. So there have been some slight changes. This was from the original work on sort of setting the two phase loading and prioritization and stuff. And like font preloads and stuff have been added to the original table. But now there's a down below way down below, keep going there.  

There's the same table where the up arrow is, if you say importance equals high, the down arrow is, if you say importance equals low. And for most things importance equals high or importance equals low explicitly puts it into the high or low, priority category. There are some things like early, media matching CSS. Even if you lower the priority of render, blocking CSS, it's still going to be high priority, mostly to prevent, shooting yourself in the foot. And then I think that might be the only thing that doesn't follow the pattern of, everything goes into high or low if you explicitly say it. And then it goes down to parser order, once you're within the same, bucket. And then the round dot is where it would naturally have shown up.

(1:08:26) Tim: Okay. And Rick and then Barry actually pointed, we were wrong. Scroll does stop the, like, it does count as the interaction. So Chrome will stop reporting on LCP as soon as user does tap, scroll or key pass.

(1:08:39) Pat: Excellent. Thanks, Rick.

(1:08:41) Tim: It's always nice to have folks kind of in this side who know what they're talking about to fact check on things like that.

(1:08:48) Pat: Yes. And Matt mentioned the, the URL is, or Earl is so memorable for that doc and you, I have to find it. I actually have to go through one of Addie's articles that talks about prioritization and click on his reference to find my own doc.

(1:09:03) Tim: Yeah. That's a thing it's I've mentioned this before. I think on Twitter, like I, the Chrome team puts out some amazing docs and they're all on these Google docs. And then trying to find them is absolute, just pain in the butt later on, because none of 'em have from URLs and yeah, it's a thing, but there's some great stuff out there. They all pump out. This was the blog post you were mentioning around priority hints. So just to, because I don't think we actually put that URL. So just to give everybody the URL, if you want to read more on priority and it does have information about the origin trial looked somewhere down here and the prioritization we just talked about Somewhere right there, then that article should help to get you started.  

Awesome. All right. Well pat, thank you for walking through, priority hints stuff, appreciate that. honestly this is like I say, this is like, because everybody should know and it's really cool, but it's like also I haven't actually sat down and like dug really good and deep into it. So this is sort of my cheat code for, unfortunately to have a chance to do it and learn about what's going on.

(1:10:22) Pat: That's awesome now instead of having to blog about it for a little while, I can point people to the video.

(1:10:25) Tim: Yeah, no that's that is helpful too. Yeah. Yeah. Right. And then everybody else can blog about all the experiments that they run on it like yes.

(1:10:33) Pat: Which bonus points I get feedback to justify shipping it.

(1:10:37) Tim: See everybody wins here. Everybody wins. Awesome. Well thanks for coming on. Appreciate it. And yeah, if anybody wants to learn more, check out the blog post or you can talk to, Pat on Twitter and I'm sure I'd be safe, volunteering you for that.  

(1:10:54) Pat: Oh yeah DMS are open.

(1:10:57) Tim: Yep. Awesome. Thanks man. Awesome. I guess next week for everybody in the US is Thanksgiving. So enjoy the, Thanksgiving break and yeah, we'll catch everybody after.


Site Speed
Core Web Vitals
Website Performance

Sign up for a FREE WebPageTest account and start profiling