Speed & Performance

A Web Performance Budget for Your WordPress Site

Pick a connection profile and a target load time, and arithmetic hands you a byte budget per resource class. A web performance budget is a decision tool: it tells you which image, which font and which plugin gets told no, before the page ever gets slow.

A Web Performance Budget for Your WordPress Site

Every performance article hands you the same verbs: compress, minify, defer, remove. What none of them hands you is a number. So you compress an image, the site feels the same as before, and you have no way of knowing whether you are finished, close, or not even started.

A page weight budget is that number. Pick the connection you refuse to be slow on and the load time you are willing to defend, and arithmetic turns those two choices into a byte allowance per resource class: this many KB for images, this many for JavaScript, this many for fonts. On a regular 3G profile with a 3 second target, the whole page gets 351 KB. Suddenly “should we add this slider plugin” stops being a debate. The plugin ships 190 KB of script. The JavaScript class has 77. No.

The point of a web performance budget is not that the number is correct. No single number could be. The point is that the number exists, everyone involved can see it, and every new hero image, font weight and tracking snippet has to fit inside it or knock something else out.

A budget is a decision tool, not an optimisation

Optimisation happens after the damage. The page is heavy, so you shave bytes off it. A budget works before the damage: it is the thing you check while the designer is still choosing between one photo and three, while the plugin is still in the search results, while the font family still has six weights ticked. Most page weight is added in decisions that took thirty seconds and were never revisited. A budget makes those thirty seconds accountable.

It also tells you when to stop. If your images come in at 140 KB against a 175 KB class budget, further squeezing is a hobby, not work. The effort belongs wherever a class is over, and on most WordPress sites that means the scripts. The calculator below does the arithmetic; the sections after it explain where its numbers come from and how to fill in yours. It runs entirely in your browser tab, and nothing you type is uploaded anywhere.

Page weight budget calculator

Pick a target load time and a connection, get a byte budget for each resource class, then put your own numbers next to the budgets and see where the page rips through them. Everything is worked out in this browser tab, nothing is uploaded anywhere.

3 s

The time a visitor waits for the page, on the connection you pick on the right.

Connection
Your page weight budget
0KB

The 0.75 factor is there because real connections lose about a quarter to TLS, headers and slow start, and the two round trips taken off the top cover connection setup and TLS. This is a planning number, not physics, and that is all a budget needs to be.

Split across resource classes

The shares add up to 100%

HTML
0 KB budget
CSS
0 KB budget
JavaScript
0 KB budget
Images
0 KB budget
Fonts
0 KB budget
Other
0 KB budget

JavaScript is not like the others

A kilobyte of JavaScript costs more than a kilobyte of anything else in this list: after it arrives it still has to be parsed, compiled and executed on the main thread, which is exactly where a page feels slow. Whoever budgets only one number for the whole page is budgeting JavaScript too generously.

WunderPaint
The Dynamic Design and Automation Studio
WunderPaint is a layered image editor for your WordPress media library. WunderPaint Studio is the same thing in any browser, free and without an account.

The arithmetic, stated honestly

The budget is one line:

budget bytes = (target time - 2 x RTT) x bandwidth x 0.75

Each term earns its place. Before the first useful byte arrives, the connection has to be built: one round trip for the TCP handshake, one more for TLS 1.3. That is why two full round trip times come off your target before any bandwidth is counted. On the slow 3G profile with its 400 ms RTT, 0.8 seconds of a 3 second target are gone before a single byte of HTML moves. HTTP/3 saves one of those trips and TLS 1.2 adds one, so two is an honest middle, not a law.

The 0.75 is a utilisation factor, and it is the honest part. A connection never delivers its nominal bandwidth for a whole transfer: TCP starts slow and ramps up, requests queue behind each other, other tabs and apps share the link. 0.75 is planning, not physics. A real waterfall wanders around these figures; the budget only needs to be conservative enough that meeting it on paper means being fast in practice.

Worked through for the default profile: 3 seconds minus two 300 ms round trips leaves 2.4 seconds. At 1.6 Mbit/s that moves 480,000 bytes, and times 0.75 that is 360,000 bytes, which is 351 KB. The calculator counts a KB as 1024 bytes and floors every figure, so the budget never flatters you. Two edge cases get the same blunt treatment: when two round trips alone exceed the target, the budget clamps to 0 KB and says in plain text that the handshake ate the whole target, and once a figure passes 1024 KB the display flips to MB.

Table of page weight budgets for a 3 second target on four connection profiles: Slow 3G allows 80 KB, Regular 3G 351 KB, Cable or DSL 1.31 MB and 4G 2.13 MB, shown with proportional bars.

Which profile should you plan against? Not your own connection. Look at where your visitors actually are: a shop with a mobile audience plans against regular 3G because that is what a train journey or a full stadium does to a 5G phone, while an internal dashboard for office desktops can plan against cable and spend the headroom. The presets exist so the choice is explicit instead of accidental, and the custom Mbit/s and RTT fields are there when you have real field data, for example from the network information your analytics records.

Where WordPress weight actually sits

The default split hands 5 percent to HTML, 8 to CSS, 22 to JavaScript, 50 to images, 10 to fonts and 5 to everything else. That mirrors where the bytes sit on a typical WordPress page, and the HTTP Archive has measured the same ordering for years: images first, JavaScript second, everything else far behind.

Images dominate because they are the easiest thing to add and the hardest thing to notice adding. A hero photograph exported straight from a phone camera is ten times the budget of the entire page on 3G. The fixes are mechanical rather than clever: size the file to the pixels the layout actually displays, pick a quality setting on the flat part of the quality curve instead of a superstition like “always 80”, and serve WebP so the same pixels cost fewer bytes.

JavaScript is second, and on WordPress it arrives in slices nobody chose: the page builder runtime, a slider, jQuery plus jquery-migrate, the analytics tag, the consent banner that manages the analytics tag. Each plugin enqueues its own files on every page it might conceivably be needed on. Fonts are the quiet third: every weight and style of a family is a separate file, so a family loaded in six weights can outweigh the hero image. Subsetting and woff2 compression decide whether the fonts class fits in its 10 percent.

Why a JavaScript kilobyte costs more

The budget treats all bytes equally because the wire does. The device does not. When 200 KB of JPEG arrives, it is decoded off the main thread and painted; the cost ends there. When 200 KB of JavaScript arrives, the transfer was the cheap part: it decompresses to roughly three times as much source text, which is then parsed, compiled and executed on the main thread, the same thread that responds to taps, clicks and typing. On a mid-range phone that pipeline routinely takes longer than the download did.

That asymmetry is why the split caps JavaScript at 22 percent even though it is rarely the biggest class by bytes. An image class over budget delays the moment the page looks finished. A script class over budget delays the moment the page works. When two classes are over and you can only fix one this week, fix the script one; it is also the class where deleting is easier than compressing, because half of it usually belongs to a plugin nobody remembers activating.

Two panels comparing 200 KB of JPEG, decoded off the main thread, with 200 KB of JavaScript, which decompresses to about 600 KB and is parsed, compiled and executed on the main thread while input waits.

Getting your real numbers out of DevTools

The Yours fields want the transferred size, not the decompressed one, and DevTools shows both. Open the page in a private window, press F12, switch to the Network tab, tick Disable cache and reload. The status bar at the bottom reports two totals side by side: “transferred”, the bytes that crossed the wire, and “resources”, what they unpacked into. The budget is a wire budget, so read the first number.

The filter chips above the request list map straight onto the calculator’s classes:

  • Doc is the HTML class, CSS and Font are exactly what they say
  • JS is the JavaScript class, including every third party tag
  • Img is the images class, favicons included
  • whatever remains (Fetch/XHR, Media, Manifest) goes into Other

Click each chip, read the transferred total at the bottom, type it into the matching field. A class you leave empty simply stays out of the verdict, so you can budget only images and scripts on a first pass and ignore the rest.

The gap between the two totals is compression, and it deserves one glance. Text compresses dramatically; images barely compress at all, because JPEG, WebP and AVIF already are compression. The front page of this site is 316 KB of HTML markup but travels as 46 KB, an 85 percent reduction from gzip alone. You can check any page of your own from a terminal, no browser involved:

# bytes on the wire (what the budget counts)
curl -s -H 'Accept-Encoding: gzip, br' -o /dev/null -w '%{size_download}\n' https://example.com/

# bytes after decompression (what DevTools calls "resources")
curl -s -o /dev/null -w '%{size_download}\n' https://example.com/

If those two numbers come back identical for an HTML page, that is a finding in itself: your server is not compressing text, and the cheapest kilobytes you will ever save are one configuration line away.

One budget per template, not per site

“My site weighs 900 KB” is not a real sentence. Templates weigh something; sites do not. The front page with its hero and its three teasers is a different document from a single post, which is different again from an archive page, and a WooCommerce product page carries the shop’s whole CSS and JavaScript baseline before a single product image loads. Measure the two or three templates that actually receive your traffic, and keep a budget for each.

The shares are editable for the same reason. A photography portfolio can justify pushing images to 65 percent and squeezing scripts; a documentation site can do the reverse. The six fields recalculate live, and if the sum drifts off 100 the total turns red while the budgets keep computing proportionally, so an honest 105 percent split does not silently break the page, it just tells you that you are pretending to have more budget than you do.

Keeping the budget alive is mostly a calendar problem. Re-measure when something changes: a new plugin, a theme update, a redesigned header. The copy button exists precisely for this; the report it produces lists budget, actual and difference per class in plain text, which belongs in the project notes or the ticket where next month’s numbers can be diffed against it. And when a class has drifted far over and nothing obvious explains it, stop optimising at random and work through a diagnostic order until you know which layer is actually responsible.

The number is arbitrary, the discipline is not

Someone will object that 351 KB is arbitrary, and they will be right. Regular 3G is a stand-in, 0.75 is a judgment call, and your visitors are not a preset. None of that matters as much as it sounds like it should. A speed limit of 50 is also arbitrary; its value is that everyone drives to the same number. The budget’s product is the word no, delivered early, cheaply and without a meeting, to the fourth font weight and the second slider plugin.

It changes the shape of performance work, too. Without a budget, speed is a rescue project: the site got slow, someone important noticed, and now a week disappears into finding out why. With one, it is bookkeeping: ten minutes with the Network tab whenever the site changes, compared against a number that has not moved. Rescue projects are dramatic and recurring. Bookkeeping is boring and permanent, and boring is what fast sites are made of.

A Web Performance Budget for Your WordPress Site

Table of Contents

Learn it by building something

Every week one thing you can make the same afternoon, from dynamic templates to 3D type. Written down step by step.

One mail a week, and then it ends.
Unsubscribe in one click.

Photo Editing

Take the scratches and dust out of a scanned family photograph

A scratch is thin and disagrees with its surroundings in almost every direction at once. A real edge disagrees in one or two. That single difference finds the damage with plain arithmetic, and an inpainting model fills what you agree to. All of it in your browser.

Photo Editing

Remove Moire From a Scanned Image: Why Blurring Never Works

A scanned magazine page shows a wavy pattern that was never on the paper: the print screen beating against the scanner's sample grid. Blurring trades one problem for a worse one. Measuring the screen in a frequency picture and notching out exactly those frequencies does not, and the workbench in this article does it in your browser tab.

Troubleshooting

Allowed Memory Size Exhausted: Where the WordPress Memory Limit Lives

The "Allowed memory size exhausted" fatal error involves three separate ceilings, and the one most people raise is not the one that stopped the request. How PHP's memory_limit, WP_MEMORY_LIMIT and WP_MAX_MEMORY_LIMIT interact, and why images trigger the error more often than anything else.

Developer Tools

htaccess Explainer: Reading the File Nobody Reads

Every WordPress site on Apache has an .htaccess, and Apache reads it on every request for every directory in the path. Here is what the WordPress block actually does, why [L] does not mean last, the difference between Redirect and RewriteRule, and which pasted security snippets have done nothing since Apache 2.4.

SEO & Structured Data

Every Character Counter for Meta Descriptions Is Wrong

A character counter says two strings are the same length. A search result says one fits and the other does not. Search engines truncate by pixel width in a specific font, and the numbers are further apart than anyone expects.

Developer Tools

Dummy Text Generator: Lorem Ipsum That Behaves Like Real Copy

Lorem ipsum has a longest word of thirteen letters and no umlauts at all, so a layout tested with it is tested with the easiest text it will ever hold. What placeholder text should actually prove, and a generator that produces it.

Download the free WunderPaint Plugin for WordPress

The WunderPaint workspace with the layers panel, adjustment sliders, text style presets and the asset library along the bottom

The Image Editor & Design Studio

Everything described here can be done in the browser, on your own site. The live demo runs the full editor with nothing to install.

Free

Chaos Art

Autonomous painters make one-of-a-kind abstract art in 3D space - gestures, art movements, painterly media, and embeds that paint a new original for every visitor.

Pro

Particle Strokes

Paint with swarms of light: twenty-two movements, a stamp you draw yourself, and curves that give a stroke a shape - the swarm keeps painting for a few seconds after you let go.

Pro

City Diorama

Any place on earth as a miniature you could hold: real streets, water and building footprints raised into a 3D diorama - or wrapped around a sphere as your own tiny planet.

Free

Papercut Art

Layered paper pictures with real depth - a photo sliced along its actual depth into up to twenty layers, parametric landscapes, animals and clouds you can shape, letters with real counters, and a look that runs on three dials.

Pro

3D Earth Studio

A hyperrealistic globe - day and night with city lights, live clouds, atmosphere halo, country borders and highlights, click-to-place markers with flight-route arcs, satellite orbits, seamless rotation video and a live website embed.

Free

Mystic Studio

Turn a birth date into wall art - a real natal chart with houses and aspects, the moon of that night, zodiac and Chinese zodiac posters, numerology cards and a synastry wheel for two, in eight artful themes.

Free

Marble Bath

Marble paper on a virtual water bath - drop, rake and comb real Ebru patterns with gestures, flowers and classic recipes, razor-sharp at any size and re-editable as a layer.

Free

Day Ring

Turn a day into a beautiful circular schedule - colour-coded time blocks as arcs around a 24-hour clock, with concentric rings for overlaps, emoji, templates and a legend.

Free

Code Shot

Turn code into a gorgeous, share-ready image - syntax highlighting, editor themes, window frames and diff highlighting - then drop it into your design as a re-editable layer.

Pro

3D Solar System Studio

Build a date-accurate 3D solar system - real planet positions for any date, photoreal textures and one slider from artistic to true scale - then drop it into your design as an editable layer.

Pro

3D Molecule Studio

Build a real 3D molecule - from a curated library, the periodic table or a SMILES string - then style it, measure it and drop it into your design as an editable layer.

Pro

3D Textile Studio

Drop your design onto cloth that behaves like the material you pick: silk falls soft, felt holds its shape, flag fabric snaps in the wind. Hang it, blow it and drape it, then lay the finished drape back into your document as a picture.

Pro

3D Particle Studio

Point the engine at any layer and it becomes a cloud of particles that keeps its colours, flowing through a sphere, a galaxy or your own outline. Keep the frame you like as a still, or embed the running engine so it keeps moving on your page.

Free

Origami

Put your own picture on the paper and watch that very sheet fold itself into a crane or a box. Every step is a station you can stop at and turn around in 3D, which is exactly where printed diagrams leave you alone.