How to check page size
Run curl -s -o /dev/null --compressed -w '%{size_download}' <url> for the bytes that cross the wire, then the same command without --compressed for the bytes the browser parses. On an MDN article that was 30865 against 258732, a ratio of 8.4 to 1.
Why check this
Page weight is a release gate on any product with mobile users or a data budget. Check it when a build adds a library, when an image pipeline changes, and on staging before sign-off. The failure it prevents is specific: a bundle ships uncompressed because one route serves it from a path the compression rule misses, and the document grows eight times with no visible change.
Two numbers answer different questions. The compressed size predicts transfer time on a slow link. The uncompressed size predicts parse and memory cost on a weak device.
Prerequisites
- curl 7.52 or later.
%{size_download}and%{size_header}are documented in the curl manual under--write-out. - Chrome or another Chromium browser, for the figure that covers every subresource.
- The MDN reference on PerformanceResourceTiming for the byte fields the browser exposes.
Steps
- Step 1.
Read the size the server declares in its headers.
curl -sI --compressed https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORSHTTP/2 200 x-goog-stored-content-encoding: identity x-goog-stored-content-length: 258732 content-encoding: br content-length: 30865content-lengthcounts the compressed bytes, becausecontent-encodingisbr. The stored length is the same document before compression. - Step 2.
Measure the bytes that actually arrive, headers separated from body.
curl -s -o /dev/null --compressed -w 'headers %{size_header} bytes\nbody %{size_download} bytes\n' https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORSheaders 3062 bytes body 30865 bytesThe body matches
content-length. The 3062 bytes of headers cross the wire too and no size header counts them. - Step 3.
Repeat without
--compressedto get the size the parser sees.curl -s -o /dev/null -w 'headers %{size_header} bytes\nbody %{size_download} bytes\n' https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORSheaders 3033 bytes body 258732 bytesDropping the
Accept-Encodingoffer makes the server send the document uncompressed, so this is the decoded size. - Step 4.
For the whole page, not the document alone, open DevTools on the same URL, Console tab, and read the navigation entry.
const n = performance.getEntriesByType('navigation')[0]; console.table({ 'navigation.transferSize': n.transferSize, 'navigation.encodedBodySize': n.encodedBodySize, 'navigation.decodedBodySize': n.decodedBodySize, 'sum of resource transferSize': performance.getEntriesByType('resource').reduce((s, r) => s + r.transferSize, 0), });navigation.transferSize 0 navigation.encodedBodySize 30865 navigation.decodedBodySize 258732 sum of resource transferSize 1692encodedBodySizeanddecodedBodySizeagree with curl to the byte.transferSizereads0and the sum over subresources reads 1692, which is the trap described below.
How to read the result
| What you see | What it means | What to do |
| --- | --- | --- |
| Compressed body far below the decoded body | Compression is working on this route | Record the ratio. 8.4 to 1 on the document above. |
| The two measurements are equal | Nothing is compressed | Check the encoding negotiation in How to check content-encoding. |
| No content-length in the headers | The response is streamed or chunked | Use %{size_download} from a GET. A HEAD cannot tell you the size here. |
| transferSize is 0 | The load came from the HTTP cache | Reload with "Disable cache" ticked, or the number is meaningless. |
Common mistakes
What to check next
- How to check number of requests on a page: the count that turns a document size into a page size.
- How to check if gzip is enabled: the first thing to verify when the two measurements match.
- How to check if brotli is enabled: the encoding that produced the 8.4 to 1 ratio above.
- How to check content-encoding: tells you which of the two numbers
content-lengthis describing.
FAQ
How to check the content-length header?
Send a HEAD and read it: curl -sI --compressed <url> | grep -i content-length. When content-encoding is present, the value counts compressed bytes. When the response is chunked the header is absent, and a GET with %{size_download} is the only measurement left.
Does content-length include the headers?
No. It counts the body. On the document above the headers added 3062 bytes on top of a 30865 byte body, which matters on a page with many small responses.
Why does DevTools show a different size than curl?
DevTools reports the whole page by default, every request together, while curl reports one URL. The panel also counts header bytes in the transferred column.
Which number belongs in a performance budget?
Both, labelled. Compressed bytes for transfer time, decoded bytes for parse and memory cost on the device.
Verified
Verified by Maks Vernycurl 8.21.0Chrome DevTools capture of 2026-09-11
Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.
Related on this site
basic5 minpublished updated Maks Verny