Our homepage's page weight was 27.7MB. We are a company that spends its days making other people's infrastructure faster and cheaper, and our own front door was shipping 27.7MB of media to every first-time visitor. It sat like that for months. Nobody noticed, because on office wifi it worked.
That is how it always happens. Assets accrete. A hero video gets exported at whatever the export dialog defaulted to. A screenshot gets dropped into a project card because it looked crisp at full resolution. Every one of those calls is individually defensible and collectively fatal, and the people who would catch it stopped seeing the page with fresh eyes months ago. The fix took an afternoon: one video re-encode, six image conversions, zero design changes. 27.7MB became roughly 1.2MB, a 96% cut, and the page looks exactly the same. Here is the entire thing.
How Much Does Page Weight Actually Matter?
Page weight matters because it converts directly into wait time. Heavy pages tank Largest Contentful Paint, burn your visitors' mobile data, and lose people before the first paint ever lands. The median web page is around 2.5MB, so our 27.7MB homepage was shipping roughly eleven times the median to everyone who arrived.
Put that in seconds. On a 10 Mbps 4G connection, which is an ordinary connection rather than a bad one, 27.7MB takes about 22 seconds to arrive. Twenty-two seconds is not a slow page. Twenty-two seconds is a broken page. Long before the transfer finishes the visitor has decided the site is dead and gone back to the search results.
The cost is not only theirs. Every megabyte you serve is a megabyte you pay egress on, and at any real traffic volume media is the largest single line in a CDN bill, which is why a page-weight audit and an AWS cost optimization review keep turning up the same files. The same discipline reappears on the infrastructure side once traffic grows, as it did when we wrote about scaling WordPress with Kubernetes. Bytes cost on both ends of the wire.
The 10-Minute Page Weight Audit
You do not need a tool for this. Open DevTools, go to the Network panel, hard-reload the page, and sort by size, descending. That column, sorted, is the entire audit. Page weight is never evenly distributed: it is almost always two or three files, and they sit at the top of that list within seconds.
Then confirm it on disk, because the Network panel tells you what shipped but not why it is that big. Two commands did the work for us.
01# What is actually heavy?02du -sh public/* | sort -rh | head0304# What bitrate is that video?05ffprobe -v error -select_streams v:0 \06 -show_entries stream=width,height,bit_rate -of default=nw=1 bg2.mp4The answer came back immediately and it was not subtle. The hero background video was 74% of the page. A single project-card screenshot was another 26%. Everything else on the homepage, every logo and icon and all the CSS and JavaScript together, was a rounding error against those two files.
That is the encouraging thing about page weight. It is almost never a thousand small sins requiring a thousand small fixes. It is one or two enormous ones, which means the remedy is proportionally small too.
Re-Encoding a Background Video: 20MB to 753KB
The video was a 3840x2160 H.264 loop running at 21.4 Mbps: 20MB for 7.6 seconds of abstract purple smoke. Nothing about that is unreasonable as an export. It is a perfectly good master file. It is a catastrophic web asset, and the gap between those two sentences is the whole lesson.
Here is the insight that makes the fix obvious. Encode quality should match how an asset is displayed, not how it was exported. Our hero video sits behind a gradient overlay and a brightness filter. Every fine detail that 4K resolution and 21.4 Mbps were paying for was being blurred, darkened, and covered with a headline before it reached anybody's eye. We were shipping 20MB of information that was, in the strict and literal sense, invisible.
So the encode writes itself. Drop to 1920x1080, because the element never renders larger than that on any viewport we serve. Use CRF 27, which sits past the usually cited visually-lossless threshold and would be an obvious compromise on a video someone was actually watching, but is undetectable under a gradient. Strip the audio track with -an, since the video is muted and looping and the audio was never audible to anyone. Add -movflags +faststart so the metadata atom moves to the head of the file and the browser can start playback while the rest is still streaming in.
01ffmpeg -i bg2.mp4 \02 -vf scale=1920:-2 \03 -c:v libx264 -crf 27 -preset slow \04 -an -movflags +faststart \05 bg2-1080.mp40607# Poster frame so the hero paints before the video arrives08ffmpeg -i bg2-1080.mp4 -frames:v 1 -q:v 3 bg2-poster.jpg753KB, down from 20,464KB. The same seven and a half seconds of purple smoke behind the same overlay, indistinguishable from the original side by side at full screen.
The second command matters as much as the first, and it is the one people skip. Without a poster frame the hero stays black until enough of the video has arrived to paint a frame, which gates your Largest Contentful Paint element on a video download no matter how small you make it. A 39KB JPEG poster paints immediately and the video takes over behind it once it is ready. That is the actual LCP fix. The re-encode just shortens the wait behind it.
If you are working through a pre-launch list rather than cleaning up after one, this belongs on it, next to the rest of the items in our guide to preparing your app for the first 1,000 users. It is far cheaper to set a media budget before launch than to discover one afterwards.

Screenshots Don't Belong in PNG
The other offender was a project-card screenshot: a 3744x3726 PNG weighing 7.1MB. It renders inside a width-constrained box, w-full h-auto at roughly 1600px maximum, so more than half of every row of pixels was discarded by the browser before it drew anything. We paid to transfer them anyway.
PNG is a lossless format. That is its entire proposition, and it is the correct proposition for exactly three jobs: images with hard transparency, logos and line art where one wrong pixel is visible, and files consumed by systems whose format support you do not control. We deliberately left our og:image as a PNG for that third reason. Social and chat crawler support for WebP previews is still uneven in 2026, and a share card that fails to render costs far more than the couple of hundred kilobytes you saved. Optimization has exceptions, and pretending otherwise is how you quietly break your own link previews.
A screenshot of a product UI is none of those three jobs. It has gradients, shadows, antialiased text, and photographic panels, and encoding all of that losslessly is pure waste. Convert it, and resize it to the width it actually renders at while you are in there, because the resize usually saves more than the format change does.
01cwebp -q 80 -resize 1600 0 screenshot.png -o screenshot.webp236KB, down from 7,270KB, with the mockup text inside the screenshot still perfectly legible at every zoom level a visitor will use. The five remaining PNGs got identical treatment and behaved identically. Here is the complete ship list.
| File | Before | After |
|---|---|---|
| hero video (bg2.mp4) | 20,464KB | 753KB (+39KB poster) |
| project screenshot (dandy app) | 7,270KB | 236KB |
| fm-erp-dashboard.png | 343KB | 28KB |
| dr-kohli.png | 275KB | 38KB |
| iarc.png | 179KB | 30KB |
| kwm.png | 171KB | 33KB |
| rectangle-13.png | 172KB | 10KB |
The Bugs You Find When You Finally Look
Here is the part nobody warns you about. When you finally open every asset on a page and look at each one deliberately, which you have probably not done since the day the page was built, you find things that have nothing whatsoever to do with file size.
Two of our project images were swapped. iarc.png showed the IARC site but was rendering on the Dandy card, and the Dandy screenshot was sitting on the IARC card. That had been live for months. What gave it away was the alt text: the alt attributes named the projects correctly, so the moment we were reading filenames, alt text, and images side by side, the mismatch was obvious in about four seconds. Alt text is a debugging tool, not just an accessibility checkbox. It is the only place in your markup where somebody wrote down what the image is supposed to be.
Two files also had spaces in their names, image_720 (12).png and Rectangle 13.png, which get %20-encoded on the wire and turn every log line, CDN rule, and cache key into something you have to decode by eye. Renamed in the same pass.
And separately, we found we were not sending Cache-Control headers on any of it, so returning visitors were re-downloading assets that had not changed in months. We shipped that fix shortly afterwards, alongside a repair to a broken GA4 tag that surfaced in the same review. Cache headers, build-time asset budgets, and CDN configuration all belong in a deployment pipeline rather than in somebody's memory, which is most of what we mean when we talk about DevOps and platform engineering.
A page weight audit is a correctness audit in a costume. You will find the heavy files, and you will also find the wrong files, the misnamed files, and the missing headers, because all four have the same root cause: nobody was obliged to look at the numbers. It is the same failure we described in why most dashboards fail. Measurement only does anything when a human being is required to read it.
WebP vs AVIF vs PNG in 2026
Format choice is a much shorter conversation than the internet makes it. Three formats, three jobs, and one of them is the default.
| Format | Compression | Support | Use it for |
|---|---|---|---|
| AVIF | Best of the three, typically 20-30% smaller than WebP at matched quality, but noticeably slower to encode | Near-universal across current browsers; social and chat crawlers are still spotty | Large hero and content images on paths you fully control |
| WebP | Strong, and stronger still once you also resize to the rendered width | Universal in browsers and supported by every CLI, build tool, and CDN you will touch | The safe default: screenshots, photos, and UI captures |
| PNG | None worth counting, because it is lossless by design | Everything, everywhere, including every crawler that has ever existed | og:images, logos that must stay lossless, awkward transparency cases |
Our homepage now runs WebP for in-page images and PNG for the og:image, which is not the theoretically optimal configuration and is the right one. The bytes AVIF would have saved were worth less to us than a slower build step and a share preview that might not render in somebody's chat client.
FAQ
What is a good page size for a website in 2026?
Aim for under 2MB transferred on a first visit, and treat that as a budget you allocate rather than a ceiling you discover. Give media most of it, something like 1.2MB across images and video, and fit JavaScript, CSS, and fonts into what is left. Budgets only work when something enforces them, so put the number in your review checklist and measure it throttled, not on your laptop over office wifi. That last detail is how a 27.7MB page survives for months.
What ffmpeg settings should I use for a background hero video?
1920x1080, CRF in the 25 to 28 range, -an to strip the audio track, and -movflags +faststart so playback can begin during download. Always ship a poster frame with it. A background loop is decoration, not content. Nobody will pause it to inspect the grain, so encode it accordingly. We used CRF 27 and landed at 753KB from 20,464KB.
Should I use WebP or AVIF for images?
WebP unless you have a specific reason not to. It is universally supported, it encodes fast enough for a build step nobody complains about, and it gets you most of the available savings. Reach for AVIF on large hero and content images where the extra 20-30% justifies the slower encode. Stay on PNG for og:images, logos that must be lossless, and transparency you cannot afford to get wrong.
Does page weight affect Google rankings?
Yes, indirectly but measurably. Core Web Vitals are a ranking signal, and Largest Contentful Paint, the one you want under 2.5 seconds, is the metric page weight destroys first. Your LCP element is nearly always the biggest image or video above the fold, so weight is not one input among many, it is usually the entire problem. Nothing you do to heading tags will rescue an LCP element that is a 20MB video.
Performance Is Maintenance, Not a Project
The uncomfortable part of this story is not that our homepage weighed 27.7MB. It is that it weighed 27.7MB for months while we shipped features past it every single week. Nobody was negligent. There was simply no step in the process where a person was required to look at the number, and a number nobody reads is a number that drifts.
Audits regress. Six months from now somebody will drop a testimonial photo straight out of Figma at 2400px wide, and the page will start creeping again unless weight is something you check the way you check tests. Put it in code review as a question with an answer: what did this change add to the transfer size? Re-run the audit quarterly. It really does take ten minutes, and it pays for itself the first time it catches a 7MB screenshot before it ships.
We build and look after fast web and mobile products, and a real part of looking after them is noticing when the front door has quietly gained twenty megabytes. If your site feels slow and you would rather have the number than the feeling, talk to us about a performance audit and we will tell you which two files are the problem.
Prefer a printable version? Download the Page Weight Audit Checklist (PDF) and run it against your own site this week.

