All right. Sorry for being a few minutes late, realized one of the things here, one of the settings in the stream thing got a little messed up. So I had to play with that. Who's all? What do we got? Okay. We got a few folks starting to come in. Cool. Hopefully those of you who are, in the US and partook enjoyed your 4th of July long extended weekend, if nothing else. yeah, so we've been doing a lot, if anybody's, if a few of you have kind of been here for pretty much every Twitch stream so far, which is amazing and a little shocking that you haven't gotten sick of me yet. but one of the things we mentioned on the last one that we kind of alluded to a little bit was, how Fastly it just blogged about how you could use, computed edge to prototype and experiment with performance, performance, optimizations, without ever touching production code and then pushing that out to webpage test.
And I know we talked about how that's possible on CloudFlare workers and Akamai and all that kind of stuff. So today I thought we'd actually try to do that, live, like, not just look at a site, but actually play around with CloudFlare workers to see, how we might be able to fix something. And what are the impact of some of these potential optimizations and, just to of try that out a little bit, I'm a huge fan of it. Like it was a game changer for me for like any performance consulting, because one of the biggest things with any audit or anything is having that predictability of those optimizations. Like being able to go to the clients or the customer and say, Hey, this is a optimization, we've got an issue with unused CSS is one thing, being able to say, we've got an issue with unused CSS and here's how you fix it is another.
But even better is being able to say, you have an issue with unused CSS, here's how to fix it. And I expect that because once we fix this, you should see roughly X, a hundred millisecond improvement in start render or something like that. Like that's the goal, the dream. Because then everybody can sort of prioritize accordingly. And it also makes it a little bit more predictable when they're making the changes. Like they know they're going to get a good impact out of it, or maybe it's not going to get, big impact. Because as I like to say that performance is a little bit like whackamole sometimes you apply on optimization and then you see these sort of other issues pop up. So being able to experiment with it on the fly without ever touching production code is huge. So that's kind of what I wanted to try and play around with this time.
So let's see here, it is summer, I am in full gardening mode. So, we can go to my I've mentioned the gardener site actually in a blog post before in a different context around CLS. But I figured we, that would be as good, a Guinea pig as any to sort of experiment with a few things. So, first up just to kind of get away of the land. This is the page, there's a little bit of infinite scroll. We've got the big hero image, nothing too like fancy or, experimental. This is your pretty typical e-com site. Yeah. If you're top talking about those little garden boxes, by the way. Yeah, they do. They do kind of look amazing. I've actually got, I I've built a few I'll that's this is not related to perf.
I've built a few garden boxes. Not quite as nice with the corner braces. I like their corner braces, but nice high ones, like good 2, 2 and a half feet of up in the air and it's amazing. I'm not even old enough to have a bad back, but like not having to bend over to weed and plant is incredible. So anyway, so fairly typical e-com site, oh no, it's always disappointing when the birds get at the veggies. I thought we would test this, just for now run a test really normal, Moto G4 is our kind of typical standard Android device for mobile testing. We’ll go ahead and use, the Chrome device emulation, which you can use on the UI or through the API. Just to keep it kind of consistent there. 4g connection. 3 test runs. We'll run first hand repeat view. Oh, we're going to label this because I think I'm going to be running a few of these. We are gardeners and I'll just leave it at gardeners because it's pretty straightforward at the moment. As we experiment with a few things, those labels I think are going to come in handy.
Oh thanks. I'm glad you liked the UI. It was kind of a big deal, right? Like webpage test has, never gotten a UI, refresh and it's what 12, 13, 14, 15 years somewhere in there. I don't even know exactly. I can't remember off the top, my head when Pat launched it. But yeah. I agree. See, editing labels in the history. We launched a few things. We just put about a blog post, like 10 minutes ago, recapping what we did like this month in terms of improvements. There were a few things around test history page, but we have other things planned and this is one of them is like the ability to, do some label editing and, or even like delete or filter out tests. Those rerunning, a test and like changing the test settings is a very common thing for folks. Like I'm assuming most of you and me as well, like as we're experimenting with, the different settings and getting that test just right, which means sometimes some of those tests you don't want lurking around and we've had a lot of requests for the ability to filter out and delete those, which I would love personally.
So that's other thing that's kind of, in the works, so expect some significant changes there and I would expect that yeah, the ability to edit the labels and the history should, be in there at some point as well. Just a matter of when that all gets, prioritized and shipped out. It's a common though. We've got some big changes there. This month though, we at least we added a few incremental things mostly this month. Like the ability before it was only searching URLs. Now it searches URLs and labels, which should have been doing, before, but that's, nice from that perspective and a couple other little small UI things. But there's more coming there.
All right. So here we have, our results for gardeners.com homepage. All right. Let's just jump down to run 2 right away. Like I said, get our, actually, I'm going to look at the film strip view just to get a better picture here right away. I like that starting point better. Oh yeah. This is one of the things we added this June, I guess its June. One of the things we added in June, I keep saying may don't I, oh man, I might be behind, this ability to compare all the runs. So like this is our median run right here, but if we click this, we should get all three of them on the film strip view so that we can compare the different runs and see, in terms of variability or what's different between one or another.
I'm pretty excited about that because that variability tends to get glossed over sometimes, especially if you focus on just the median thing. So having, there's a lot of insights that can be gleaned from that though. So that was kind of a cool new addition. I don't think we had, the last time we were doing this. So this is our film strip we'll switch it to 0.1 second interval. And just because core web vitals is hotness will highlight, largest contentful paint as well. Because that looked like that was problematic on our summary for this one. Like let's go back really quick. I vow to clean up my tabs this time as I go maybe for a little bit. Yeah, so our largest contentful paint is problematic. Total blocking time, firs contentful paint there’s a bit of a gap between that. And our first bite would suggest there might be some optimization we can do there as well.
And it looks like our LCP on this test is slower than what we're seeing in crux field data, fairly substantially in this case. So we could probably bring the network up or the device, maybe even a hair up that being said, it's not like LCP or FCP are good in the wild, right. They're in that needs improvement range. So I don't mind if we stress tested this a little bit and got things a little bit slower. I'm more concerned about the opposite. Like if we find a situation where LCP looks really good in webpage test and the field data shows that we have problems, that's more problematic to me. Stress testing is awesome because it just sort of highlights, all those gaps and weaknesses in the app that you'd be missing otherwise. So I'm not too fussed about it being a little slower.
You’ll watch this. So what happens here is you make those request out to type kit. and then type kit is going to come back, inside of the, like it, you have to go through this whole connection to get to that CSS file to begin with, but then to be able to get to the actual, font declarations themselves, we have this P type kit as well, which is another connection out to get the CSS, I guess this isn't as bad as like, oh, what's the one, is it Heffler or something like that does a whole CSS redirect, which makes things even more slow. But even with this, we have these two third party requests for, connections being made to go out for CSS, which is an ideal, jQuery coming off of third party CDN. Okay. So we've got, we've got, those are sort of the obvious ones jumping in the, like stopping us from being able to get something out on the screen.
Oh, question about which ad requests are blocking rendering generally just like a good starting point is to do what I'm doing here. Grab the film strip, find out when your initial render hits that page or when key content hits the page, look at where that red line lines up and any request that comes after that, or is completed after that you don't have to worry about it. It's not really blocking display of the page at all. You're only focusing on the stuff prior. Then in this stuff prior to that, as of Chrome 92 and with some improved that's coming in 93, Chrome provides a render blocking status, which should give you some indication. I've mentioned this before on the other streams, but we will make that more prominent in the UI once Chrome 92 comes out in a couple weeks here.
I guess Chrome 91 is when it first shipped. There's a bit of a bug though. So we haven't made a lot of noise Chrome 92, when it comes more stable, will make this a little easier for you to spot, but clicking through for now and looking at render blocking status should be a pretty good clue for you if it's, blocking or not. so that, and again, the film strip is a powerful way of seeing that because if it comes after, if it's completed after you get stuff on the page, it's not blocking you're rendering and you don't really have to worry about it from that perspective, at least. All right. So we know we've got these requests here, that are kind of delaying that first contentful paint. Let's go a little bit further out, see when our largest contentful paint fires where do you fire?
Oh, there you are. 10.8 seconds. Now this is a quirk or it's a thing with largest contentful paint, largest contentful paint. You'll notice the image appears to be there for a while. it's not going to fire until that image is fully processed and download it and, and put into place, which means that if you're using anything like a progressive JPEG where it's coming in layer by layer and scanning that in and filling in all the pixels as is going, which might be really good for perceived performance might not. It's been a little inconclusive about that. But LCP, isn't going to fire until that is image fully arrived and processed, which is why for this test, we see the image actually much earlier. I mean, still, four and a half seconds in is when we start to see it, but it's not really until that 10.8 where it finishes loading.
And if we go down to our waterfall here, we can see the hyphenated green line, which is where LCP. And we see probably nope, one of these images that is lining up pretty close to our red line. There it is. Yeah, so this image here lines 62, is what's triggering that. And that's about when that image stops downloading, good question on the page test internals. It is not puppeteer. Webpage test has its own, sort of testing agent that, Pat built. we do have a lot of the commands available that we expose in webpage test scripting that are familiar to from Chrome dev tools, protocol, that puppeteer exposes as well, but we're actually running our own sort of agent underneath, which has the ability to not just test on Chrome, but safari and Firefox and edge and brave and all that other stuff as well. So there's, quite a bit of power and it's collecting, everything that the browser is doing, throughout the process there. So there's, a ton of information that we can surface and collect that way.
All right. So we know that this image is triggering RCP, looking at the waterfall. It's a little bit of a bummer that it's this low, its line number 62. Whoa, are you seeing this? Is that my, no. Okay. For a second, my screen is doing some weird stuff. Line 62 is not ideal. It’s also a relative lead large image at 172 pixels. It's just more so that it's so far down that waterfall. if I were to go back now that we've kind of got that picture here and go back to the test run itself, and I'm going to jump to the core web vitals diagnostic page, just because the visualization on largest contentful paint will be handy there I think.
Here we can see it highlighted in the waterfall. That's the exact request. But up here we see the details and yeah, so it's a background image. So what's happening here is the browser's downloading the HTML downloading the CSS, has to process all of that CSS. That's this purple that you see down in the main thread section, has to process all of that right before it can even discover that image and make the request. So that's why this image is pulled in so late. Okay. So we've got a few things. I think we've got a decent bearings, we have a few things going on, around third party stuff, delaying that first content full paint, which, if it's delaying first contentful paint, it's also delaying largest contentful paint. We have a background image that is triggering LCP, which means it's not being downloaded until late in the page.
I think there is some optimizations that come to mind that we could play with and let's see if we can make it work with CloudFlare workers. So for anybody who's not familiar, CloudFlare workers are they're little chunks of serverless code that run on the edge, which means they run on a CDN server somewhere. CloudFlare workers, is Cloudflare's version of it. Fastly has computed edge, Akamai has edge workers. I think its edge workers. Edge computing I guess, is sort of the umbrella term for these things and it's becoming increasingly common. and it's really powerful because what it lets you do is it lets you take, a piece of code and dynamically alter, whatever is coming back from your server before it gets to the browser. So, client side AB testing. You could move that to the edge instead.
You could still programmatically make all sorts of funky decisions at the edge, but you apply it on the CDN server where it's faster and the network is faster and the machines are suped up versus having to apply it inside the browser on the user's device, which is where it's unpredictable and probably a lot slower. So one of the cool things that you can do, I mean there's a lot you can do in production. One of the cool things you can do with this in conjunction with webpage tests though is you could take CloudFlare workers or computed edge or Akamai's edge workers and pair it with webpage tests, custom scripting to apply, changes to the document on the fly, right before you run a webpage test, which means that we can experiment with optimizations and we can try to apply different things and see how they, pan out when we're testing them. I'm using CloudFlare workers. It's the first one that, kind of came out, there's a good docs around CloudFlare workers and there's some good articles from Matt Hobbs and Andy Davies, Pat Meenan has done a talk on it. There’s a lot of good resources around it. But again, you could use Fastly or Akamai, whatever you're more familiar with.
So I'm going to show, the code for this quick and see if we can get things up and running. Let me switch this over. All right. This is the code for a generic CloudFlare worker that works with webpage test. I do not know on cost by the way for Fastly or otherwise. So I mean workers, I know there's a free tier of workers. I don't know if Fastly is free, if it comes built in, if you're already, already paying for it, worth checking with them. For sure. So this is the script from CloudFlare workers we'll walk through it a little bit here. this is, I took this is the script that Andy Davies put out on his blog post, as he notes here in the comment is also, piggybacking off of Pats. Just going to show that, everybody builds off of somebody else's ideas. It's sort of a Daisy chain here, which is cool. It’s one of my favorite things about not just perf, like it's the web people, always putting stuff out there on the blogs and you learn from other people and you kind of iterate on top. It's just, it gets it me happy. It's my happy place.
So walking through this, we're just going to right here. This is declaring which site we're using right now. We’ll change this. This has to be, gardeners.com is the site we're going to be proxying through. Right here we an event listener, which is listening for fetch events. And when a fetch event occurs, it's going to respond with, handle request. That's the, function, the method that we're going to use to do all of our alterations and figuring out what to do with the requests. And we're just going to pass the request through. So handle request is where all the work is actually happening. You can see that's the bulk of this script. We get the request we're grabbing out the URL. Mostly what we're using this for at the beginning at least is to figure out like, do we want to proxy anything through, and override anything, some stuff to disallow the crawlers.
here's where the webpage test stuff starts to come in when webpage tests, there's an override host command in webpage test, scripting, which will show in a little bit when we use that in webpage test, when that gets applied, webpage test does apply. It does set an ex-host header to tell you what the host was. And this is helpful from you just, from validation perspective for testing and things like that. For our situation here, this is beneficial because we can get that and use that to sort of compare like first off, is it present at all? And if it's not present, we probably don't want to mess with the proxy. Like we really only want to use this proxy, like in testing environment. and so that's why, you'll get the 403, like if it's not being proxy through webpage tests, don't even try doing any sort of funky CloudFlare stuff.
and the other thing we can do with it is sort of compare that host to the site that we have up here again, to make sure that we're only applying Optimizations where we expected to apply optimizations. We don't accidentally have this applied somewhere we weren't anticipating it. Andy added in this bypass transform, which is if we wanted to skip the transformation of the HTML entirely, it's still used the CloudFlare worker, just a sort of level set. We could set a custom header, and if that's present, just skip transform, we're not going to get into that today. Basically we're going to make sure that this site is the same site we want to test and then we're going to here. You can kill that that's not really necessary. This is where the magic's going to happen. What we're going to use is we're going to use HTML rewriter, Cloudflare's API for rewriting and manipulating the HTML itself. And then we're going to, here's where we could apply all sorts of different transformations. I'll show you some in a second. But you basically Daisy chain, these ons, and then at the end apply the transform and send it over. And that's about it.
So if I go to CF workerssandbox.TimKadlecworkers.dev, I'll drop that in chat for anybody who wants to sort of play along, actually might not be able to play long, I forget I had this turned on. Actually if you go to this, what you'll notice is ex-host header missing, that's this check that we had in place, right? That was saying like, check to see if there's actually ex-host header. If we're actually trying to proxy this through, to test this, what I like to use is this mod header extension. y'all, can't see the mod header's extension can you? Why is Chrome not given you an extension view here? Interesting. Maybe I'll switch this to the All right, well here. This is a really handy little extension that lets you set up request headers that you can toggle on and off. And so for testing CloudFlare workers, I have a, ex host request header that I set. And then I just set that to just like in the actual index or worker script, I set that to the URL that I'm trying to go to. So the host of the URL, so gardeners.com in this place.
If I have that in place with mod headers and I hit refresh, now I should see the Gardnersupply.com or company site because we've got that ex-host header present. And that's what it's telling that URL to load. All right. So now we've got this it's up and working. We have a proxy. It's not doing anything now, but let's show how we can run that inside of webpage test. So let's go back to webpage test. We’ve got gardeners.com. We're going to need to use a little bit of, custom scripting here. So we mentioned the override host command. That's going to be the first thing we're going to do. I have this set up as a keyboard shortcut because I forget everything.
So what we've got is over by host, we're going to use this host, variable substitution, and what that does is it says grab the host of the URL that we're testing. And then we're going to override that host to instead refer to CFworkers-sandbox.com like, sandbox.TimKadlec like the whole worker URL. And then, we need to navigate command, which should be, navigate URL should be our drop in, our replacement there for the variable substitution. And let's just leave it at that, and test really quick. Oh, I forgot to change the label. I told y'all labels were important and I was going to do the thing, but the labels and then I didn't Man. All right, that's fine. Do, as I say, not as I do people.
Oh yeah. So, Rafael, we don't do a ton on the server. if you're talking about webpage test in terms of like testing the backend side and available resources and stuff there no that's not really, webpages forte, is capturing basically that front end side of things and the network as well, to some extent, but less so on server availability. Particularly because we are using our own server instances. So, we're not I guess, from an origin server, I suppose, eh, no, because we don't necessarily know exactly what's going on, on your origin server and the way this is working. We're sort of picking it up after the fact. So we don't have a lot of insight there. So we're probably not the most useful for that kind of thing that you're going to need to do your own server load testing and stuff like that. It's a little bit different tooling.
All right. Here's our test result. Let's see if it worked, we'll look at the waterfall. Perfect. So you can see that now instead of gardeners.com, everything is coming from this CF workers sandbox, Tim Kadlec. So this means things are proxied now through CloudFlare, by itself, this is kind of boring. Like Woohoo, we got a different domain. We haven't actually changed anything yet. So let's make this a little bit more interesting. First without touching the worker, the first thing I want to do is I want to experiment with these third party domains. So each third party request, we have to go through this SSL plus TCP, or DNS resolution plus TCP connection plus SSL negotiation. That's this teal orange and purple bars that you see in front of each of these third party requests.
Now each of those things slows down like that takes time slows down. The connection slows down our, our delays, our render blocking. It also takes away from HTTP two's ability to say that 10 times fast HTTP two's ability to use prioritization. To say like, okay, we have all of these different kind of resources coming over this one network connection. Let's use prioritization to make sure that the high priority ones get over faster, lower priority ones, come into our a little bit later, that kind of thing. Like once we move it to all these separate connections, we lose all that power as well. So in the world of HTP 2 in particular, this is problematic.
So the first thing I want to do is experiment with taking away these third party requests. Like what if we were able to self-host, all of these now, I don't know enough about like power reviews to know if we can self-host I know we can, self-host Google fonts. We could grab the font itself. We're not going to go quite that far for now. We'll just Oxy, the URL through our own, code.Jquery. Of course we can do that. And I think the same with font. Awesome. You know, it's pretty safe bet that we can self-host all that. So I think it's a pretty realistic test rather than again, mess with the worker script. What we're going to do is we're just going to go back and modify the webpage test script that we had applied. And we're going to do this. We’re going to add, I don't remember how many oops errant character in there. Okay. That's good enough start.
I'm basically going to proxy each of these things through to our CloudFlare worker script. So we'll do UI power reviews. We had fonts, Googlesapis.com. We had use that type kit, and then we had what P dot type kit. Yep. What both of those. And we had co judged JQuery. And finally it was what pro.fontawesome.com. Yep. So I think that covers all of these initial connections, should be all right. Let's drop that in here. All right. So all we're doing now is we are adding to our, so just like we proxied gardeners supply through the CloudFlare workers domain, we're going to proxy each of these third party resources through to imagine what it was like if we had, all of these things, self-hosted. And then this time we're going to set a label because that's nice proxy are third party. So let's go ahead and hit the test for that one.
Which one was this? This is our proxy, this is our, we're going to order these a little bit while that's running. This was our initial test. We'll drop that over here. Proxied without manipulating anything was that, and this will be our proxy, our third parties. So, okay. We'll see a couple questions they're happening in parallel and not blocking the FCP kind of. They’re I assume we're talking about those connections. Sorry. I didn't see exactly when you dropped that question. They are happening in parallel. They're definitely like most of them. If we look at power reviews, it kicks off just a little bit before the rest of 'em. The timing for each of them seems pretty darn close. You know, it's not like any one of these is taking significantly longer than the others. and they are getting open kind of right away, as soon as they're, identified, they are still blocking first contentful paint though, because each of these are run blocking resources. So the time that it takes to go out and connect to those servers all that connection cost is a delay in first contentful paint.
So for example, let’s look at profontawesome. If I click on that, I can see my DNS was 880 milliseconds connection hundred 67 SSL negotiation, 184. So if we add all that up together, we've got what 2, 3, 465. Is that what 500 milliseconds is that right? Somewhere in there 500 millisecond delay. So if we didn't have to make that connection, that CSS gets down 500 milliseconds faster, which shifts things over. Now, if we shift just that and kept all the other third parties, we still probably have this slow FCP, but if we shift them all the theory is we should get a faster first contentful paint. The question on the sub-domains from the same origin. So sub domains, it depends on the SSL negotiation actually, it's all about the SSL certificate in the IP address of those sub domains. They have to kind of go back to the same source and if they do not resolve to that same, IP address, then yes, they're going to cause additional handshakes, which is not great.
All right, let's go to our run here. It looks like it's done. So right off the bat, our largest contentful paint does look like it's faster. Our first byte is a little faster too, so we can't chalk it up entirely to the optimization. We got about a 400 millisecond faster, first byte in this time. And largest contentful paint improved by about a second first contentful paint by about 900 milliseconds still. So let's click run 3, our median run and have a look there at the waterfall. So now you can see all of these things were well there's one little funky thing there we'll get there. All of these requests, like the jQuery stuff that was on those third party origins are now moved to the first party. And so we don't have that upfront connection cost. So everything shifts over.
Because everything shift over earlier, we get a little bit faster first Contentful paint and largest Contentful paint. So the one that jumped out here that we still see this little connection, and that is for all dot CSS. Which one was that? Is that the font awesome one? It was. So why do we have a connection cost there still probably cores, cross origin something resource, something cores. Security stuff. Basically, let's look at the request for one of the ones without the connection cost. Okay. That's a no cores mode. Yeah. Okay. Cross origin resource sharing. Is that what it is? Something like that. So in this case, we are apparently doing something that's requesting causing this to open another connection, because we've like because of the cross origin setting for this particular, request. So let's go to this source and let's see if we can find our font awesome.
Okay. So see, y'all can see that, hopefully right here, we've got this cross origin attribute now because it's requesting an anonymous connection. It has to open up another connection. This is good, important for a third party request probably makes good sense. In this situation, we are now proxying this, we're assuming this is a first party request. So we don't really, in reality, if we're self-hosting this, we don't actually need to pay that cost. We can clean that up easily enough, I think, inside of the worker itself. So let’s do this. We're going to switch back to our worker so we can show this is where the fun stuff comes in.
The question about using this approach to show customers performance impact. If they decide to use CloudFlare with all performance features, you can use it to show the impact of all sorts of different optimizations and get them applied. I don't know if you can, like, I haven't tried programmatically. I don't know if you can, programmatically enable a bunch of different CloudFlare features inside of a worker. That'd be, be clever. It'd be nice. I'm not sure if you can like say enable this on this page or not. I'd have to look at that. It's a good question.
All right. Let's get rid of the cores thing. So we're going to go to our HTML rewriter and what we're going to do is Pat says there is a request header to toggle that's nice. All right. So what we're going to do here is we're going to remove the core, cross origin attributes. So the first thing I need to do is I need to say on finding this element, and in this case, our element was the, font awesome thing. So what I'm going to do is grab this the Href value hold. And I'm going to say on link is that right? That's right, right, right, right. Somebody fact check me. Yeah, that looks right. Okay. So we're going to say on this is using like those CSS attribute selectors, which is super nice. So this is, you know, CSS skills for the win.
We're going to say, when we find an element that matches this selector, what we're going to do then oops, is we will grab the element. Which I think is just This. So grab the element as L how original and we're going to use, there's a, remove attribute. There we go. And we're going to remove cross origin. Now I should, with that saved, I'm going to publish this quick. So it gets up there. Okay. With that in place, what I should be able to do is as soon as that goes wherever it needs to go in CloudFlare land, I should be able to come back to this, page with that mod header's extension running again, and actually see this in effect. It should actually break, I think. Cuz here we're not doing the actual proxying right here. We're doing that inside a webpage test. Yeah. So this console issue here is, telling me it worked. It’s complaining because there's an integrity attribute, but that mean, but there's no cores attribute anymore. So I think we're in business. So if we go back here again and look for all.CSS. Oh, does it just see it removed from the final? That's fun. How does it, where are we at here? It was all right. Yeah. All, Oh, I forgot to switch back to my browser. Sorry Y'all.
What I was saying is we come back here to the browser. I went to that CF workers where we had the mod headers extension running again. And you can see right away, I get the console error, because we've removed cross origin. It sees the integrity attribute, but Hey, that doesn't apply if cross origin is there. So we've got an issue. So that means great. Our proxy worked, or our code worked. So we should be able to come back here and actually just rerun that same test, we don't have to modify our script here in any way. And we can just say just the never ending label, it's going to get longer. This is like V1 V2 V3 V final. It's basic it's, that's where we're getting ourselves closer to here folks.
We’ll let that run. But basically we saw in this other window, its working, right? Like we pulled off the cross origin thing. This isn't like super necessary, I guess, but it does give us just that cleaner waterfall so we can see, again, a little bit more realistically, in clear cut, like what is the impact of potentially ho hosting self-hosting, all of these third party resources. And that'll take just a second to run. Gotta tell you its handy having an ex, CloudFlare employee in the chat to field questions around CloudFlare stuff. It’s nice. Thanks pat.
So I'm not expecting a major difference from this last test where we were at, you know, that 5.2, you know, if we assume the first byte is going to be reasonably close 5.2, I'm not expecting to be significantly faster. We’re just offsetting that little bit of connection cost up front there to hopefully clean it up. And I expect a little bit of a change in first contentful paint and start render. But again, you know, not like massive. Yeah, sure enough. A little bit faster. First byte is pretty much identical. Our start render is about a hundred milliseconds faster, first contentful paint, a 100 milliseconds, faster, largest contentful paint, just under a hundred milliseconds, like 67. Okay. So minor, which is what we kind of figured was going to be the case. But now if we look at the waterfall, we can see the connection cost for, Eh, yeah. That's the one right. Font. Awesome. Yep. Is we no longer have the cross origin thing going on in the separate connection cost there?
So cool. We have a nice clean waterfall now everything is coming from first party. We've seen that this actually has a pretty good impact on first contentful paint and largest contentful paint. The next thing I would be keen to play on based on what we were talking about here is if we can get this largest Contentful paint element, which was this pest control thing to fire a bit earlier. So we had two problems. One is that it's in the CSS. Another is that there's just a ton of other requests above it. Like there's all these other images that are coming into play, and being requested earlier.
These are some of these are big, big-ish 63 Megs, 112 or 63K 63 megs. Woo. That'd be bad. 112K 145. Yeah. So there's some hefty images. So all of these are coming. They're getting requested a little bit earlier cuz they're in the HTML. Which means they get kicked off. They contend with for bandwidth and this gets pushed down quite a bit. So one of the first things we could try to play around with here is, maybe some lazy loading. So if we go back to our summary, let's go to our film strip view for this one again. God, I love that film strip view. Yeah. Okay. So we have what a logo and this hero image, which is our LCP background image and that's it, the other images don't ever, they're not in that initial view part.
So let's play around with what happens if we lazy, loaded those other images. Now there's the loading attribute for those who aren't familiar. So there's now this, where are you? Come on. Nope. Loading, Come on. There we go. Loading attribute, which we can apply to images or eye frames. And we can say, you know, load this lazily we don't want to apply it. We, this is a great thing to, like apply to anything that's outside of that initial visual viewport. So going back to our page, that means anything basically that isn't the logo, the logo is the only content image above the viewport, for our test. So what we can do is we can figure out what the source is for this element and apply a transform inside of CloudFlare workers. That basically adds the lazy attribute, the loading attribute, I'm sorry for at everything, but that image.
So let's grab our source. If that doesn't make sense, hopefully it does after we show the code and let's go back to my code and we're going to Daisy chain, another rule for transformation here. So in this case, we're going to look for the image with that source, I think. Yeah, let's do actually, we're going to look for the image that doesn't have that source, right. So that's not, source equal or I guess I can copy paste. We have good. That should get her done. So let me see here what we're saying is image that is not source equal to this source. Yeah, that seems about right. And again, that CSS selector stuff. So if you're coming at this, from that CSS background, that syntax probably looks pretty familiar to you, if not. Yeah, it's a good thing to brush up on.
So in this case, what we're going to do then is set attribute and loading lazy. All right. So this should set the loading attribute to equal lazy for all images in the HTML that are not that first image. We don't want to set it on that first image because we want that to load right away. We don't want to delay potentially the loading of that image in any way, hopefully by lazy loading. Some of these, I don't know, if this is going to have a, the other issue with our tests here, right? Was that it was CSS. It’s coming from CSS, which means it's actually getting discovered a little bit later too. So I'm not sure if this is going to have a huge impact or not. I have a theory on what we could try that might be a little better, but in the sake of science, let's run it one at a time.
We will publish that up. You can't see that, but what I'm doing is just in terminal. I use their CLI tool for this, which is called Wrangler and it's fantastic. Just hit Wrangler publish and it goes up in just a matter of seconds. Sorry, gal here what do you mean by skip the LCP image? Oh, oh for the lazy loading attribute. You're right. If it was in the HTML, it's not like this image pest control MC dot JPEG does not exist in the HTML itself. It is coming from CSS. It's a background image, not a content image. So it actually, you know, will not get this applied to at all. What we're doing here is manipulating just the actual images in the HTML itself, not the actual CSS. So we should be okay here, otherwise. You're right. We wouldn't want to lazy load that either. And you're jumping ahead almost to what I think is going to be our bigger win here.
So with that in place, let's see if we can reload our page and see if we've got our lazy attribute in place. So I'm going to do command shift R and again, that you don't have to do the mod headers part. I like doing the mod headers bit here, like just to validate that my stuff is working before I fire off webpage test. Suppose you don't really have to do that though, if you want to just wing it and just see how it goes. So I don't see a lazy attribute on logo, which is good. Let's go down to an image down here. Nah, look at that. There's a loading equals lazy attribute now on the other image. So I think we're in business. We can grab another image maybe down below here. Yep. Loading its lazy. Great. All right. Yay. I legitimately get excited about that. Lazy.
I'm serious. Like, I don't know, like this combo to me, like the ability to manipulate stuff without ever touching their code. Like I have no access to their code base. Did I just yeah. No access to their code base whatsoever. So the ability to still play around with these optimizations and apply them on the fly is absolutely freaking fantastic and super exciting. Low quality image placeholders. So for those who aren't familiar like the idea there is that you've got a big, you know, high resolution image. Right. So to get things to load faster, what you do up front is you load you smaller image or an image that's a low quality kind of blurry. I think this is kind of like what medium does with basically everything. Well, they're not going to do it now. Did they get rid of it or is this because I've been here to this page before? Or is it my thing too fast? And I'm fine making me look bad. Oh yeah, no, there as I go down, it was pretty fast because my network's quick, but it starts off blurry. It's a lower quality thing. And then the higher quality comes in anyway.
The idea is to give you these smaller images up front a little bit faster load. In theory, I like the idea out, its kind the same thing with progressive JPEGs. Like give some visual indication of the image coming. Even if it's a lower quality to make it feel faster. So in theory, that's awesome in practice we don't have good evidence on this yet. Like I think there was one study that was done around progressive images and, and I don't think the findings were particularly conclusive nor were they particularly like encouraging on the impact of these kinds of things. And anecdotally, I've heard a lot of folks who get really frustrated by the process actually. stay tuned on that space cuz I think there's some experimentation potentially coming soon to try and put some more data to this, but right now it's one of those optimizations that if you're going to try it and apply it, you need to back that up with testing of your users because we're not seeing conclusive evidence yet that it's a good idea. And in some cases it may actually, be causing problems.
Pat's not going to talk to me for the rest of the day. Thanks everybody. All right. So going back to our test here. Okay. Look at the, Ooh yeah, look at this. This makes me happy. Okay. So here is our last test that we just ran where we, did some lazy loading of images. Let's go back to the test before and do some comparison. All right. So our first bite time is actually a little slower on this run. Our first content full paint, nearly identical 2.979 to 2.966. We weren't doing an optimization that would've impacted that. So I would expect that to not change. Here's the kicker, largest Contentful paint went from 5.267 seconds to 3.489. I like this. This makes me happy. So let's go to run 2 and see the waterfall and see why that might be. And we'll go back here to our run as well and look at the waterfall.
So originally our largest contentful paint image was in this case request 51, pretty low down the queue down here. It's now bumped up to request 38. Yay. So it's requested, it's still identified after the CSS, but it now bumped up the queue because all of these other images are pushed down below because they're lazy, loaded. We don't need them right away. We've told the browser that, so they get deprioritized. And so now we've bumped our background image up the queue and in the process we shaved what 1.5, 1.8 is that right? Tim's tries to do math live. That's always great. Yeah. 1.7 seconds or so off of our LCP, like that's a pretty big win. Just by applying what is ultimately just a little bit of HTML?
So this is great. Like if we were going to gardeners and saying like from an optimization standpoint, we've now tested 2 like self-host, your third party stuff. We can show that it actually has a demonstrated impact on first contentful paint and start render. And then we've tested adding this late, easy attribute. And again, we can show that this one is a significant winner for reducing that largest contentful paint. That’s awesome. So yeah, that's great progress. Okay. So if we wanted to bump LCP further, I think what we'd have to do is we have a couple of things still pushing it out. Like there's still in the CSS, so it's still not discovered until CSS is all downloaded and parsed. And that means that process is a little delayed right now because we have two CSS files here that don't get re quested until after, I think these were the Type kit ones, I think. Right?
So logo was in the HTML and you can see it is requested. That's this one here. It does get kicked off a little bit earlier then the pest control MC. So if we were able to remove, to move this image itself into the HTML, rather than into the CSS, we would potentially see a little bit of a boost, discovered at 2.5 seconds in the HTML. Whereas pest control is discovered at 2.6. So we'd see about a hundred millisecond or so improvement. You know, nothing too awful dramatic.
Like I said, the bigger thing is these darn PCSS ones here pushing out, because like we can't do anything until the CSS comes through. We can't display anything. And we've got, I'm assuming this is like coming off of an import from this one. Let's see. Yeah. You're going to complain because it's the, what is that P.typekit.net, right? Anybody remember? Nothing. Okay. So that's just an empty CSS file. All right. So let's go up here. Let's find the original type kit offender. Come on which one was it? See, this is the problem now with, well, let's go back to our original test. This is why we keep it around. Use that type kit, QKC blah, blah, blah. That's right. QKC, blah, blah, blah. Well I just don't see it all. Do I know? Am I missing it? Oh, there it is right in front of me.
All right. So let's pull up this URL. I want to see what's inside of this thing here. You see what type kit is doing? Bunch of comments. Ignore that. Yeah. Yeah. That's the problem right there. It is the import. So I did. Okay. Any more imports? All right. Imports are not great because what happens with import here is CSS is render blocking. The browser tries line the CSS as early as possible that's why you have all these CSS files requested upfront. Now it grabs the CSS file for Type kit. It starts to parse the CSS. And when it does, it says, oh, hey, we've got this import. I need to go make another CSS request and I need to import this thing here. It goes out and makes the request and pulls that in. Well, this is also render blocking. The browser couldn't discover it until later on.
Like if it's a practical solution there, the other thing we could do is potentially, I don't like, like preload is a bit like the important, like CSS thing. Like you shouldn't use it in anger, I think is what, Harry Roberts always says about important and your CSS. I think it's sort of with preload, you gotta be a little careful with the it, but this might be a situation where preloading, this image might help us out. So let's try it. Yeah, let's try it. All right. So we're going to go back to our page. We're going to grab, or no, we're going to stay actually here. This was what pre 21. Let's grab our full URL for now. Okay. And go back to our code. All right. And add one more transformation here. So now we're going to say, now this doesn't exist in the HTML, so we need to inject this in there. So what we're going to do is we're going to say on head, Oops. Spelling
Okay. So now we've got this, we're going to create our preload. I think we have to make this go back to gardener supply though, because I think if we don't, I don't think it's going to work. I think we need that here. Cuz the proxying for this is happening on webpage test side of things. So let's drop the sandbox URL out use gardeners.com instead. And oh, and then we gotta add the add as image, which I always forget to do that. It's bad. I don't want this here yet. And okay. So there, so we've got a preload, preload, this image, as an image telling, the browser, what kind of resource we're pulling in.
Let’s go ahead and add that to the page we're going to do. In this case element dot we have two choices. We could append this to the end of the head or we could prepend it to the beginning of the head. We’ll prepend I guess, and then we need to tell it that it is HTML, like prepend, not just as world text, but as an HTML. Okay. So on head element. So when it sees the head element, create this text, prepend it to the start of the head, and apply that transformation. Okay. That should get the job done. He says he thinks, he thinks we'll find out.
So get that published up again and come back over here. Chrome's been weird for me lately. So like first, which it's not abnormal for Chrome to be weird. Oh no, here we go. With dev tool stuff. Oh no. Did I kill it? Maybe I did. Did I? What did I do? Oh, you're right. Thanks Keller. Yep. So a hundred percent it's L there you go. That'll do it. I think given the number of typos that I do and like writing and coding and just in general, I should just always have somebody watching to be like, hey, you did this, you used the wrong, name, or you left out a period. It would be very handy.
It's like a, what's that Marvel? Has the, like the Watchers, right? The people who watch, like, it would be nice to have Watchers for coding. I could, I'd pay for that service I think. probably gets a little creepy, but if you're doing that every day, all day, but still cool handy, I guess maybe initially for a little bit I'm rambling. All right. So now with that applied, we reload our page. Let's see if our pre-load is inside the head. Great. All right, so let's run a test here and see what pre-load did in this situation.
Gardner's preload. Yep. Okay. That still had my script intact. I didn't close anything there. Nah, we're good. We're good. We're good. Cool. So preload is one of those things, by the way, I highly recommend reading. I think Andy, Andy should pay me for dropping his name so many times. , we should be paying him for the content. Maybe, that's the better approach here. Andy has got a great post around preloading specifically around fonts, which is one of those situations that everybody kind of, yeah, maybe a co-pilot thing, right. Applies preload to. But it it's highly recommend digging into this. It's really, really good about some, like some of the gotchas around preload, and where it's not necessarily as helpful as, we initially thought maybe. And now that I say, that, [inaudible1:10:43] I'm not going to remember this. I wonder if I saved this to my site links. Preload? Yes. Sweet.
Yeah. [Inaudible1:10:59 ] from Google has a really, really good I'll drop this in the chat Google doc that kind of walks through their own sort of experimentation around preload and when it can work and some of the problems and things to watch out for. So preload is one of those optimizations where, if we're looking at the stuff we were doing right now, I was pretty sure lazy loading would apply positively how much, how positively, like how much of an impact I wasn't sure but I expected it to be a good thing. Same with self-hosting. I expect that to be a good thing. How much was what we needed to measure.
In this case I suspect preload is going to make an impact for our largest continental paint. What I don't know is if it's going to potentially negatively impact some of those other metrics, because preload can have that effect. You're jumping you, you're pushing other things out. And so that's why this is just a really good candidate for kind of doing this experimentation up front. So this is our, I think our preload one. Yeah. I can see the little purple. Okay. So this is our preload and this is the one prior. So let's kind of do a little bit of metric comparison really quick. We’ll come up with actually a better way too, in a second here. First contentful paint looks a little slower, could be other things going on largest Contentful paint is definitely faster. We jump from 3.5 to 3.0.
And if we click on run one, we see our image is queued up right away. It doesn't have to wait for anything to find it. Which means as soon as the CSS is in place, we're able to get that out onto the screen. Now this is a really good candidate for comparing this test and the prior test using the plot full results page. Yeah. So switch to the browser. Good call. Sorry about that. This was just my, way of sort of building up sort of dramatic tension. No, this is the test result that we just saw, the brand new one. This is for us preloading. So if we click on run one and look at the waterfall, the image is right up front. Like it's the first thing requested preload gets it right out the door. So we're no longer waiting for all the CSS. The image is there. And as soon as the page is able to display, the image is going to be displayed in full, which is why our largest contentful paint sees a really nice jump here. We're down to three seconds from 3.5, to the test condition exactly prior to this.
What we don't necessarily know is if there's bad fall out in other cases like our first contentful paint before is actually a hair faster than it is now. Same with speed index. Those could be anomalies, they could be something legit. So this is a good candidate for looking at these plot full results. So what I'm going to do is, grab, I guess, the test one, the test URL, and I'm going to go to WPT-compare.app. This is Matt Hobbs page that he built. So we're going to do, I guess what CSS image for the first one, we will grab the URL for our summary of our second one, where we did preload. We're going to drop the add in for test URL 2 and get rid of that. And that's with image preload, going to generate a URL and do our comparison view.
So, what this does, and we're going to also make sure that we're comparing against, the CSS image, because that's kind of our baseline in this case. And I'll force vertical access to start at zero. So what this is going to do is it's going to take each run for each of those two test scenarios and plot out the data. Ideally I'd run more test runs to compare this, to make sure that we really have like a good standard, comparison here, but yeah, this is still better than nothing. So in this case we can see image preload does look like it's faster, but statistically significant on first contentful paint. No. So this is actually a good sign because this is one of those metrics we saw get worse once we started preloading and it looks like it's not a statistically significant regression, at least with only three test runs. Our largest contentful paint is a statistically significant improvement, with preload in place, which is awesome. That's what we were hoping for.
We actually see, an improvement it and not statistically significant, but we do seem to see an improvement in CLS as well. Total blocking time looks like its pretty much, in line with what it was. So we're not seeing a lot of regression on any of these other metrics now again, to know, for sure, like run like, more test runs, run nine or whatever, just to add a little high of certainty, but even just from this, I would say that this optimization seems to be worth pursuing. It seems to improve largest contentful paint. Doesn't seem to have a significant impact negatively on other metrics.
Yeah, so that's not, that's not bad. That is the, and again, this is like that combination of, being able to use the webpage test scripting, which is pretty straightforward in this case, we're just overriding and sending it to a CloudFlare worker proxy. And then pairing that with, the worker itself, which there's not much going on. These were three simple little transformations, but from those transformations, what we saw was basically taking largest contentful paint down from 6.3 seconds on that first run to three seconds, we literally cut it in half. And along the way, we made improvements to first contentful paint, as well, speed index too. So yeah, it's not bad for three little optimizations. And I guess this is again, and now if we were going to gardeners, the nice thing about this is we can say, hey, these are optimizations. You can actually apply. And we have a high level of certainty. Like we know they're going to positively impact performance. It’s not just us saying, like, I think it's going to be an improvement. We can say, look in our tests, we show, cutting it in half by applying these three things.
That is much more helpful for them because then you can actually go back at this organization and say, Hey, this is a potential big impact for us. We should give this a lot of priority versus, an optimization, like moving in into the HTML, which based on our guesswork at least didn't look like it was going to be significant. And that was something that you didn't want to waste time doing necessarily when there's other bigger tickets, kind of lining up. Pat, what do you got next level, but would be nice to eliminate the cores Json request in, in the API response directly from the worker at the edge. That would be nice. Yeah.
Oh, what time is it? It's already an hour and a half in. Why are people still here? I appreciate that. I'm just, I'd be bored of me. I respect that. That makes me feel good. All right, hold on. So what pat is saying is like, if we're looking at, where do we go after this? Right. So looking at our last test, what's still potentially slowing us down? Well, we mentioned the CSS thing, like one thing to play with would be just killing those. Honestly, these are tracking, I'm going to do it because it's annoying to me. And we can figure this out pretty. Can we just do, let's do this. Hold on. Yes. We have these two PCSS ones which are just for tracking. We’re going to block those.
So there's a command in webpage scripting, which is block and you just pass at a string and any request that matches that string will block it. P.CSS is a super vague string, but just looking at, yeah, I know for the marathon, you all can drop off, dude. I'm sorry. I'm just, no, this is me geeking out. But from the looks of all the requests here, that was the only couple that like had the, that matched the PCSs thing. There were only two requests that match it. And those are the two I want to block. So I'm going to head in block those. This is not what pat was talking about. I just nerd sniped myself
Anyway. So while that's running in the background, because I think that's going to speed up our first contentful paint quite a bit as well. Like we've got these darn imported CSS requests that are pushing out our initial render. What Pat's talking about is we could do inside the worker as well is since this is now a first party request, we don't need the cross origin stuff again. Just like we removed cross origin for, the font awesome request. We can see this is being fetched with core is enabled. We could pull that off again, here, which would speed up that like get rid of in this case, what do we have for that kind connection cost another, hundred sixty eight, three hundred and seventy milliseconds or so, kick that out of there, which would be nice. And the other thing, oh, were you saying inline the, API response itself? So potentially both pat is what you're saying.
So like potentially remove the cross origin that one's pretty straightforward. Alternatively, what we can do is we can actually request this JSON. What's the response look like? Do we have it? No, let’s do gardeners.com. Am I typing this right? That doesn't look right to me. That's right. Okay. Now where'd you go sunshine?
That was gardeners.com, right? Like the, eh, didn't like it what's the response. Oh, look at this. It's actually like, there's nothing to it. We should be just like, this is like an 11 byte, thing, which is headers. That's why it there's like nothing going on here. We could probably just kill this as well. I'm not even sure be curious like what this is doing, even if it's there for track or whatever. So we don't even need to inline the, the JSON response in this case, the JSON response is just nothing. We just delete that request entirely. So we could actually add that to our little block list would be a quick way of doing it without having to touch anything inside of, the CloudFlare worker at all.
So blocking the P.CSS stuff, which is what this test was. Yeah. Like this, this is 2.6, which is, I think our closest so far was what, 2.9 for first contentful paint. Yeah. 2.9. So we just cut off another 300 milliseconds. Now we're down below three seconds for our largest Contentful paint. Now we're down to 2.8, shaving a way even more. That’s not, yeah, that's awesome. I don't know why I talk to myself in auto tune during the day while I'm doing this, by the way. But I do, that's like, it's not even at tune it's not really singing. It's kind of half talking, half singing. Yeah. Anyway, things that you learn when you watch somebody just live, do something.
Actually this one, again, we could grab that and we have two ways of doing this in CloudFlare workers. We could actually pull this out entirely and remove the element. In this case, it's probably just as easy to script it here, inside a webpage test, and just say block the request. And just have that excluded from the waterfall either way works. And here it's 2.7. I mean the JSON, this is one of those again, where now we're starting to get into like tweaking hundreds of milliseconds here a little bit by pulling that out. So we'd want to do like a good decent test size here and compare the results to see if there's an impact. The waterfall does look a lot nicer without that little JSON thing taking up space though. That's for sure. Yeah. So that's, again, one of those situations where we'd run maybe nine tests or so look at the plot full data, see what the actual comparison is looking like there. Yeah, not bad.
Cool. So, we could go further. I mean, obviously we could play with a whole bunch of stuff here around some of these other scripts that I think are getting in the way, still of an initial render, potentially, maybe what is this carousel thing? No, it's a little pride. It might not be blocking. It's not too bad there. That might just be our CSS time. It is. It's just our CSS time. So from here you could start to experiment with like maybe what, if you lazy loaded some of the CSS, like some of it doesn't need to be there on load maybe, or, does the UI. JS thing? What if we pulled that thing out and deferred that or something like that? There are things we can play with and experiment with and CloudFlare workers would let us do it without, running into production.
And again, just to reiterate, if you got Fastly play with this on Fastly, if you've got this in, Akamai, play with it in Akamai, yes. We could do some edge caching of the HTML. Like there's a ton of different things we could start to do inside the worker. for the sake of letting y'all get back to, your Workday, I think we'll cut her here, but yeah, hopefully this gives you a bit of a taste of how, that edge computing, solutions being provided by the CDN is compare with webpage tests to make a really powerful performance testing in experimentation platform.
So, if you got questions, feel free to fire 'em otherwise, thanks for tuning in again. We’ve got, I think next week, actually, I'm going to do an audit on somebody else's channel learning with Jason. I'll do something there with him. And then I think after that, we've got a couple guests coming up in the near future, where we'll do at least one of those will be very audit focused. But another one of those, I think we're looking at building some stuff out. So, it'd be nice too, to have somebody who's not Tim, on here as well. So yeah, we'll get a nice little I think there's a few fun ones coming up.
Corgi, trains and bops. That's a learning with Jason thing, the corgi trains thing. I've only watched like one. Like I'm familiar with him. He's done like some, I know the quality of what he does is really, really good. And he's had some awesome casts, but yeah. Yeah. Okay. Corgi, trains and bops so much to learn. See ya. Thanks everyone for tuning in.