← Insights

Shopify page weight: what a product page weighs, where the bytes go, and the budget to hold it to

The median mobile page is 2.6 MB and a Shopify product page carries it somewhere else. Two sizes, a sourced budget, twenty minutes in DevTools and two commands.

13 min read

Contents — 7 sections

Page weight is two numbers, and the phone pays for the larger one

Page weight is the sum of every byte a browser receives to show one page. The Web Almanac defines it as the total volume of bytes transferred to the device, and that is the number a network throttle acts on and the number most tools report. It is not the number the phone has to process.

Every text resource, which means the HTML document, every stylesheet, every script, the JSON the theme embeds and the SVG icons, travels compressed. Shopify's platform page says the CDN minifies CSS and JavaScript and compresses files with Brotli and gzip. The browser then decompresses each file and parses the original. So every text resource has two sizes, and Chrome's Network panel shows both once Big request rows is switched on in its settings: the transferred size on top, the uncompressed size underneath. Its own example is a document that came down the wire at 43.8 KB and unpacked to 136 KB.

On a Shopify product page the gap is wider. The audit script we run before a teardown records both numbers for the product page it fetches, and the case that made us record them separately was a document that arrived at 164 KB and decompressed to 1,051 KB. Six times, and the two mean different things: the first is what a slow connection waits for, the second is what the main thread parses before anything renders. Compression shrinks the download, not the parse.

Images and video are the exception, because their compression is part of the encoding and the transfer size is the real one. The Almanac's caveat is about what happens after: a 200 KB image decoded into raw pixels can occupy 5 MB of memory. Its one-line summary of the split is the one to keep: 100 KB of an image is pixels, 100 KB of JavaScript is work.

The median mobile page is 2.6 MB, and a Shopify product page carries its weight somewhere else

The 2025 chapter, published in January 2026 on data from July 2025, puts the median mobile home page at 2.6 MB, up 8.4% on the year, and the median mobile inner page, which is what a product page is, at 1.8 MB, split by type:

ResourceMedian, mobile inner page
HTML20 KB
CSS80 KB
Fonts119 KB
JavaScript660 KB
Images354 KB

The median mobile page makes 68 requests, 22 of them for JavaScript and 12 for images. Home pages carry 911 KB of images against the inner page's 354 KB; JavaScript is much the same on both.

The same chapter puts a cost on the total. Among mobile home pages under 1 MB, 72% reach a good Largest Contentful Paint; in the 2 to 3 MB band, where the median sits, 59% do; at 5 MB and above, 44%. On mobile, LCP by weight band runs from 2.6 seconds under 1 MB to 3.8 seconds at 5 MB or more, against Google's 2.5-second threshold. Weight is not the only reason a page misses it, but the lightest band is the only one that gets near it.

A Shopify product page is not shaped like that median. Our own sample, 25 product pages in our two markets, measured with the audit script rather than taken from a published source, has a median of 398 KB of decompressed HTML, 16 script tags in the head, 2 third-party script hosts and 7 images without intrinsic dimensions. The Almanac's 20 KB of HTML is a transferred figure and ours is decompressed, so they are not the same measure, and even at six to one the Shopify document is several times the web's inner-page median on the wire. The reasons are in the theme, and the section on the document below names them. The document is the one resource that cannot be lazy-loaded, and on Shopify it is the one most people never weigh.

Every published budget is below the median, so write one down before the design does it for you

A performance budget, per web.dev, is a set of limits on the things that affect speed: the total size of a page, its load time on a mobile network, the number of requests. It exists so that the argument about a hero video or a fourth webfont happens against a number rather than a mood. The starting figures web.dev gives are under 5 seconds to interactive and under 170 KB of critical-path resources, compressed, on 3G.

Lighthouse's network payload audit flags a page whose requests total more than 5,000 KiB and says to aim below 1,600 KiB, what a 3G connection can deliver while still reaching interactive within ten seconds. The 2024 Almanac cites a harder target from the Performance Inequality Gap series: 365 KB for a three-second load at the 75th percentile, 650 KB for five seconds, and that assumes a JavaScript-heavy page.

One thing no longer exists: Lighthouse's own budget file. The 12.0 release lists the removal of budgets, so the budget.json workflow older guides describe does not run in a current Lighthouse. A budget is a document you write and a number you re-measure. Ours for a product page, on mobile, first load, with the source of each line:

LineBudgetWhose
Total transferredunder 1,600 KiBLighthouse's target
Critical-path resourcesunder 170 KB compressedweb.dev's default
The LCP imageunder 200 KBours, from the hero image post
The HTML document, decompressedunder 800 KBours, twice our sample median
Any one app's script10 KB compressedShopify's suggested limit per extension
Third-party script hosts8 or fewerours, the sample maximum
DOM nodesunder 800Lighthouse warns at about 800, errors at about 1,400

Shopify's own numbers sit behind two of those. The theme app extension configuration reference enforces 100 KB of Liquid per extension and suggests 100 KB of compressed CSS and 10 KB of compressed JavaScript; the Liquid limit fails a deploy, the other two are suggestions. The Theme Check linter ships AssetSizeCSS and AssetSizeJavaScript checks at 100,000 and 10,000 raw bytes, measured on the file as written rather than as served, and neither runs until it is added to .theme-check.yml. The Theme Store bar, a minimum average Lighthouse performance score of 60 across home, product and collection pages, is measured on Shopify's benchmark store, and says nothing about yours with fourteen apps on it.

Twenty minutes in DevTools gives the total, the split by type, and the three heaviest files

Use the best-selling product page, not the homepage, in Chrome. Open DevTools, choose the Network panel, tick Disable cache, and in the panel's settings tick Big request rows. Toggle the device toolbar, set the viewport to 390 by 844, and set throttling to Slow 4G, which Shopify's mobile guide specifies as 1.6 Mbps down, 750 Kbps up and 150 milliseconds of round trip. Then reload, because the panel only counts requests made while it is open.

The total. The status bar at the bottom of the panel shows three figures: the number of requests, the bytes transferred, and the bytes of resources, which is the uncompressed total. Write all three down. At 1.6 Mbps, 2 MB of transfer is ten seconds of the connection before parsing starts.

The split. The filter bar has a type chip for each resource kind: Doc, CSS, JS, Font, Img, Media. Click each in turn and the status bar re-totals for that type. Six rows, two numbers each, and the Almanac medians from the table above beside them. The row furthest above its median is the finding.

The three heaviest. Clear the filter and click the Size column header to sort. The top three rows, with both of their numbers, are what to write down. A hero image at 1.8 MB, a slider library at 300 KB, a document at 900 KB uncompressed: each is a sentence a developer can act on, and "the page is heavy" is not.

The apps. Under More filters, tick 3rd-party requests, and the status bar shows how many of the requests come from origins other than the page. Sort those by Domain and the vendors sort themselves. Shopify third-party scripts covers pricing each one in milliseconds and what to remove first.

The cross-check. Run Lighthouse from the same DevTools on mobile. Avoid enormous network payloads lists the largest requests first; the Optimize DOM size insight replaced the DOM size audit in Lighthouse 13; and the image delivery insight lists every image that could be smaller.

Two commands weigh the document the way the audit script does

DevTools measures the whole page. The audit script measures one thing about it, the document, because that is the resource nobody else reports and the one a theme is most responsible for. It fetches the product page as itself, asks for compression the way a browser does, keeps the compressed length, decompresses the body, and records both. The same two numbers from a terminal, with the product page's address in URL:

curl -sL -H 'Accept-Encoding: br, gzip' "$URL" | wc -c
curl -sL --compressed "$URL" | wc -c

The first prints the bytes that crossed the wire, Brotli-compressed the way Chrome asks for them; the second prints the bytes the browser has to parse. The -L follows the redirect most stores put on the bare domain. On the page we tested this on, the two came out at 167,755 and 1,818,483, a ratio of nearly eleven, and neither is the number a character count of the page source gives you.

The script's threshold is 800 KB decompressed, twice the sample median, and when a page crosses it the finding quotes both figures, because a sentence about what the page ships is a claim about transfer and a sentence about what the browser parses is a claim about the other number. A page under the line gets no finding. Its value is that it asks the one question the free tools skip.

For the theme's own files, enable the two size checks in .theme-check.yml and run shopify theme check: every stylesheet over 100,000 bytes and every script over 10,000 bytes is listed with its path. Those are raw sizes, so a script that compresses well still fails, which is the right direction to be wrong in.

On a Shopify product page the weight sits in four places, in this order

Images, and mostly the gallery. Shopify's responsive images page is the mechanism: without srcset and sizes the browser has one file to choose from, and a phone downloads the desktop one. The image_tag filter with a widths list and a sizes string writes the srcset, the width and the height in one call; a theme that builds the URL by hand for one width does not. Two things the CDN does for free and one it cannot. Per the image_url reference, it detects which formats the browser accepts and serves WebP or AVIF from a JPEG upload, and it takes a quality between 10 and 90, which the CDN guide says to leave unset unless you have measured a smaller file at a specific value. What it cannot do is resize a file in the theme's assets folder, so a banner uploaded there is served at its export size; move it to Files and pass it through image_url. The gallery's remaining problem is a theme that preloads every slide rather than the one on screen: the first image is the LCP candidate and loads eagerly, the rest are lazy. Shopify hero image size covers the export itself.

JavaScript, and mostly apps. The Almanac's median inner page ships 660 KB of it on mobile, and its Lighthouse runs found a median of 251 KB uncompressed that never ran. On a Shopify page the theme's own bundle is usually the smaller half; the rest is apps, each asked to stay inside Shopify's suggested 10 KB and none subject to a total. The Lighthouse Treemap, which Shopify's worst offenders guide recommends as the first ranking, draws every script as a box sized by bytes, and the three biggest boxes are rarely the three the merchant would have guessed.

The document. Three patterns account for most of a heavy one, and Shopify has a page on each. A variant picker that loops product.variants renders every combination into the HTML; Shopify supports 2,048 per product, and the variant page replaces the loop with options_with_values and fetches the selected variant through the Section Rendering API. A duplicate mobile and desktop menu makes a navigation element of 500 to 2,000 nodes; one menu styled by media queries halves it, and a hybrid that renders top-level links in Liquid and fetches submenus on hover removes the rest. Hidden components, the cart drawer, the size chart, the filter panel, sit in the live DOM whether or not they open; a template element holds the same markup at zero nodes until first use.

Fonts. 119 KB at the median, and a DNS lookup and TLS handshake before the first file if they come from a third-party host. Shopify's font page puts the library first: a font_picker setting with font_face and font_url serves the file from the same origin under the CDN's fonts path. Self-host only when the typeface is not in the library, and then ship WOFF2 with a WOFF fallback and nothing else.

Video is the fifth place on any page that has it. The Almanac found QuickTime the heaviest file type on the web at a median of 976 KB on mobile home pages, and an autoplaying hero video is the largest file on every store we have seen one on. A poster image and a tap is the same shot at a fraction of the bytes.

Fix it in this order, and the first pass is an afternoon

First, the measurement: the six-row table from the Network panel and the two document numbers from the terminal, twenty minutes, and the baseline everything after is compared to. Second, the gallery: re-export the hero, confirm image_tag is writing a srcset and the slides after the first are lazy, an hour, and usually the largest single drop. Third, the apps: the third-party filter, the leftovers in the theme, and the Treemap, half an hour to list and a decision per app. Fourth, the document: the variant loop, the duplicated menu and the hidden components, half a day for a developer, and the only step that moves the parse number rather than the transfer number. Fifth, fonts, an hour. Sixth, the budget table, written into the theme's readme with today's numbers next to each line, and a repeat of step one a month later, because public field data is a 28-day rolling window per Shopify's lab and field guide, and an app installed in between will have moved it.

Weight runs through all four causes in why your Shopify store is slow, and the images half is the part most stores can finish without a developer. If you would rather have the page weighed, the three heaviest files named, and the fixes ranked against everything else the store is losing to, that is the Store Teardown: €750, five days, and the document is yours whatever you decide to do with it.

Own your growth.Start with the teardown.

Start with a Teardown. Read it, then decide whether you want us to fix what it finds.