Resources
The method
How we go from downloaded bytes to an estimate of the CO₂ emitted
Contents
The measurement protocol
Grammage opens the page in a real browser and lets it live as it would at a visitor’s, always following the same protocol, called grammage-1. Everything that follows is therefore fixed in advance, and this is what allows someone else to repeat the measurement under the same conditions and find the same bytes.
The conditions
| Setting | Value |
|---|---|
| Browser | Windowless Chromium, driven by Playwright |
| Identification | a user agent that ends with Grammage/ and the version number, so that a host can recognise it or let it through |
| Phone, by default | 412 × 823 pixel screen, density 1.75, touch screen, Android 11 agent, processor slowed down four times |
| Computer | 1,920 × 1,080 pixel screen, density 1, processor at the pace of the machine |
| Network | the connection of the machine that measures, with no throttling or added latency |
| Passes | three per page, and the report keeps the median of each quantity; the fast mode only does one |
| Maximum duration | five minutes per pass |
The network is not throttled, which does not change the bytes counted but can change what a page decides to load depending on the speed of its connection, and we come back to this in the limits. As for the phone processor, it is slowed down four times to look like a mid-range model.
The five steps
| Step | Setting | Limit |
|---|---|---|
| Loading | until the browser announces that the page is loaded | one minute at most |
| Waiting for calm | one second with no network exchange and with less than 0.05 s of processor time, checked every 100 ms; if the processor never settles, three seconds without network are enough | fifteen seconds at most |
| Scrolling | a mouse gesture with a step equal to 1.6 times the height of the screen, a pause of 150 ms between two steps, then the same step by script when the page blocks the gesture | at the bottom of the page, or after 30,000 pixels or 45 seconds |
| Observation | everything that still happens is counted, and the idle processor time and bytes are recorded | three seconds |
| Return visit | the page is reloaded with the cache filled, and only what is downloaded again is counted | one reload |
Scrolling is used to trigger everything that only loads when you get close to it, such as deferred images. When a page blocks the gesture, as a consent banner often does as long as it has not been answered, Grammage scrolls it by script, as EcoIndex does, without ever answering the banner, neither to accept nor to refuse, and the report says so. The measured page then looks more like the one seen by a visitor who refuses cookies. When the content scrolls inside a large block of the page rather than in the window, as in some applications, it is that block that Grammage scrolls.
The initial load and the whole page
Grammage keeps two views of each pass. The initial load gathers what arrived during loading and while waiting for calm, so before scrolling, and it is the one the score compares, because that is how the HTTP Archive measures the pages our benchmarks come from. The whole page adds scrolling and observation, and it is the one carbon counts, since what a visitor makes the browser download while scrolling down also counts for energy. An image loaded only at the bottom of the page therefore does not weigh on the score, just as it does not weigh on the benchmarks, whereas it does weigh on the carbon estimate.
What is recorded
| Quantity | What is recorded | Use |
|---|---|---|
| Transferred weight | the bytes that travelled over the network, compression included, as in the Network tab of a browser | initial weight (score) and whole page (carbon) |
| Requests | their number, a redirect counting as one request more | initial (score) and whole page |
| DOM elements | their number, counted as EcoIndex does, without the inside of SVG drawings | initial (score) and whole page |
| Hosting | the answer of the Green Web Foundation, and the country of the server deduced from its IP address by RIPEstat | score and carbon |
| Fifteen rules | the good practice checks, made on the middle pass when the passes are ranked by weight | score |
| Computing time | the processor time of the whole visit, scrolling included | shown, not scored |
| Idle activity | the share of processor and the bytes that a scrolled page still consumes when nothing more is done | shown, not scored |
| Unused code | the JavaScript downloaded and never run, the CSS that no element uses, in transferred bytes | shown, not scored |
| WebSocket frames | what a chat widget or a live feed exchanges, counted apart from the weight | shown, not scored |
| TTFB, FCP, LCP, CLS | the speed of the first byte and of the first paint, and the stability, recorded before scrolling | shown, not scored |
| Return visit | the share of bytes downloaded again with the cache filled | shown, not scored |
The pages of a site and their templates
Grammage tests one page when it is given its address, and the score it returns then only applies to that page. For a whole site, it reads the sitemap, or follows the links of the page when there is none, then keeps three pages per template and fifty in all, and each one is measured as a separate page, with its own score.
| Setting | Value |
|---|---|
| Pages per template | three at most, for example three blog posts |
| Pages per site | fifty at most |
| Sitemap, if the site has one | the addresses it declares, and the groups it declares take precedence over any grouping |
| Without a sitemap | the links of the page, with three visits at most per measured page |
| Hidden templates | from twelve addresses at the root, the HTML of eighty of them at most is compared, and three or more pages that are at least 80% alike form a template |
| No site result | when more than a quarter of the pages could not be measured, or when the cap left entire templates with no measured page |
The template is first read from the address, so /blog/an-article and /blog/another-one share /blog/*. When a site puts its pages at the root, the address no longer says anything, so Grammage compares the skeleton of the HTML, the tags and classes of the content without the text, the header, the menu or the footer. An application drawn in the browser, whose HTML is almost empty, is not grouped this way, and without a sitemap the same grouping is done on the page rendered while following the links.
The weight of each page in the site
The result of the site, its score, its average carbon per page and its average initial weight, is the average of its measured pages, in which each one counts for the share of the site it represents. A product page measured among three, on a sitemap that has two thousand of them, thus weighs about 667 pages, and the home page weighs one. When the site is discovered through its links rather than through a sitemap, the size of each template is not known and each page counts equally. Since Grammage does not know the traffic of each page, the carbon of a site is an average per page of the site, never per page view, and nothing is said about a whole site from its home page alone.
Pages that cannot be measured
A page that answers with an anti-robot challenge, the one from Cloudflare or DataDome, or with a refusal from Akamai, Imperva, HUMAN or Kasada, is declared not measured rather than scored, since what would have been weighed is not the real page. In our corpus, these services refused twelve of the thirty online shops and six of the thirty news sites. A customer whose site is protected this way adds to the allow list of their service the agent that contains Grammage/, because Grammage never tries to pass itself off as a human visitor.
From weight to carbon
Directly measuring the energy a page consumes, at each visitor, on each network and in each data centre, is impossible from the outside. Grammage therefore estimates it with a published model, Sustainable Web Design in its version 4, which the collective of the same name maintains and which the CO2.js library of the Green Web Foundation implements, in its version 0.19. The model starts from the bytes transferred, translates them into energy spread between the data centres, the network and the visitor’s device, hardware manufacturing included, then translates that energy into carbon with the intensity of the electricity.
The constants of the model
A gigabyte here is one billion bytes. The model spreads 1,581 TWh per year, of which 1,021 for use and 560 for manufacturing, over the traffic of the Internet, and it obtains 0.300 kWh per gigabyte, that is 0.194 for use and 0.106 for manufacturing.
| Segment | Use, kWh per GB | Manufacturing, kWh per GB | Annual use | Origin of the total |
|---|---|---|---|---|
| Data centres | 0.055 | 0.012 | 290 TWh | IEA 2022, midpoint of 240 to 340 |
| Networks | 0.059 | 0.013 | 310 TWh | IEA 2022, midpoint of 260 to 360 |
| Visitors’ devices | 0.080 | 0.081 | 421 TWh | Malmodin 2023 |
| Total | 0.194 | 0.106 | 1,021 TWh | traffic of 5.29 ZB in 2022, ITU |
Manufacturing is counted in terawatt-hours of electricity equivalent, which explains why it is then multiplied by an intensity like use. These totals come from estimates that differ a lot from one source to another, and with another traffic denominator, the use coefficients of data centres and networks would be about 20% higher, which is why carbon is kept as an estimate and not as a measurement.
The formulas
GB = bytes / 10⁹
use U(s) = GB × ε_use(s) × I(s)
manufacturing F(s) = GB × ε_manufacturing(s) × 494
first view = U(centre) × (1 − H) + F(centre) + U(network) + F(network) + U(device) + F(device)
s the segment: data centre, network or visitor’s device
ε the energy per gigabyte from the table, in kWh
I the electricity intensity of the segment, in g of CO₂ eq. per kWh (494 by default)
H 1 when the host is recognised as green, 0 otherwiseUse takes the electricity intensity of the segment, 494 g per kWh by default, the world value of the 2022 Ember set that Sustainable Web Design recommends. Manufacturing always keeps 494, even when a local intensity is set, because almost all digital hardware goes through a worldwide supply chain. A host that the Green Web Foundation recognises as green only removes the electricity use of the data centre, never its manufacturing nor the rest of the chain, which takes 0.055 out of 0.300 from the world factor, that is 18.3% of the total.
Grammage counts a first visit, so without any reduction for the cache, which matches the CO2.js defaults for version 4. This is the figure, the most cautious one, that Grammage puts forward and that the badge displays, because it depends on no assumption about your audience and it can be compared with the Web Almanac statistics, which use the same calculation. It counts the whole page, scrolling included, whereas the score only looks at the initial load.
A step-by-step calculation
Take a page that transferred one megabyte, that is 0.001 GB, to a host that the Green Web Foundation does not recognise as green, with the world intensity of 494 g per kWh everywhere. The data centre consumes 0.001 × 0.055 kWh of use, that is 0.000055 kWh, which we multiply by 494 to find 0.0272 g, and the same operation is repeated for each segment and for manufacturing.
| Segment | Use | Manufacturing |
|---|---|---|
| Data centre | 0.0272 | 0.0059 |
| Network | 0.0291 | 0.0064 |
| Visitor’s device | 0.0395 | 0.0400 |
| Total | 0.0958 | 0.0524 |
Use and manufacturing added together give 0.1482 g, which comes down to 0.3 kWh per gigabyte multiplied by 494 g per kWh, that is 148.2 g per gigabyte. A page of 2.4 MB gets 0.356 g in the same way.
| Assumption | Carbon | What changes |
|---|---|---|
| Non-green host, 494 everywhere | 0.148 g | the figure that Grammage puts forward |
| Green host | 0.121 g | the use of the data centre, 0.0272 g, disappears, that is 18.3% less |
| Audience and server in France, 31 g per kWh | 0.058 g | use falls to 0.0060 g, the manufacturing of 0.0524 g does not move |
The local estimate
Next to the main figure, the report gives a local estimate, which uses the electricity of the country of your audience for the network and the device, France by default, and the one of the country of the server for the data centre when it is known. The country of the server is deduced from its IP address, and when it is not known, the data centre keeps the 494 g of the world. Manufacturing always stays at 494, so that, for an audience and a server in France, use becomes almost negligible and the result hardly depends on anything but manufacturing. This estimate never replaces the main figure, because it depends on assumptions that we choose, but it gives an order of magnitude closer to the reality of a French site.
| Area | Intensity | Source |
|---|---|---|
| World | 494 | default value of Sustainable Web Design, 2022 Ember set |
| France | 31 | Electricity Maps, 2025 annual average |
| Sweden | 21 | Electricity Maps, 2025 annual average |
| United Kingdom | 176 | Electricity Maps, 2025 annual average |
| Germany | 342 | Electricity Maps, 2025 annual average |
These annual intensities are those of 2025, built into CO2.js, and France illustrates their fragility well since Electricity Maps gives 60, 91, 49, 33 then 31 g per kWh from 2021 to 2025. Finally, the report translates the grams into equivalences drawn from the public factors of ADEME, in kilometres by car or in web searches for example.
Putting the grams in context
The verification page places the grams of a site on the Sustainable Web Design carbon rating scale, per view. The steps are inclusive, a page of 0.079 g is still an A.
| Step | Grams of CO₂ eq. per view |
|---|---|
| A+ | up to 0.040 g |
| A | up to 0.079 g |
| B | up to 0.145 g |
| C | up to 0.209 g |
| D | up to 0.278 g |
| E | up to 0.359 g |
| F | above 0.359 g |
Categories and their thresholds
An online shop does not have the same needs at all as a presentation site, so Grammage never compares a page with the whole web but only with the pages of its category. There are six of them, and each one has its own benchmarks, taken from the Web Almanac data, the yearly HTTP Archive study of millions of sites. Since the Web Almanac sorts sites by technology rather than by kind, each category takes up the technologies that fit it best, and its benchmark is computed from them.
| Category | Sites taken as benchmark | Web Almanac technologies |
|---|---|---|
| Presentation | sites made with a static site generator | Jekyll, Hugo, Astro, Eleventy, Hexo, Pelican, Gatsby |
| Documentation | documentation made with a dedicated tool | Docusaurus, VitePress, VuePress, Mintlify, Nextra |
| Showcase | sites made with a general-purpose content management system | WordPress, Wix, Squarespace, Drupal, Joomla, Duda, TYPO3 CMS, Craft CMS |
| Editorial | blogs and publishing sites | WordPress, Drupal, Joomla, Ghost, Tistory, Hatena Blog |
| E-commerce | online shops | Shopify, WooCommerce, PrestaShop, Magento, Wix eCommerce, Squarespace Commerce, BigCommerce, OpenCart |
| Application | web applications built with a framework | Next.js, Nuxt.js, Gatsby |
How the category is chosen
Whoever measures can declare the category, with the --category option of the command line or the category field of the API, where it is showcase by default. They can also write auto, and Grammage then deduces the category of each page itself, rather than letting someone pick the most lenient one. To do so it reads what the page already publishes for search engines, its schema.org types, in JSON-LD or in microdata, its og:type and its generator tag, as well as the platform it has recognised. It looks for the hints in the order of the table, and the first category for which it finds one wins.
| Order | Category | Hints |
|---|---|---|
| 1 | E-commerce | the types Product, ProductGroup, Offer, AggregateOffer, OnlineStore or Store, an og:type equal to product or starting with product., or a recognised Shopify or PrestaShop shop |
| 2 | Documentation | the types TechArticle or APIReference, or a Docusaurus, VitePress, MkDocs, GitBook, Starlight, Nextra or Sphinx generator |
| 3 | Editorial | the types Article, NewsArticle, BlogPosting, Blog, Report or LiveBlogPosting, or an og:type equal to article |
| 4 | Showcase | none of the previous hints |
The presentation and application categories are never deduced, they have to be declared. Each page keeps its own category, so on the same site a product page is compared with product pages while the blog article is compared with articles, and the report states through score.context.inferred when the category was deduced.
Where the benchmarks come from
Each category has two weight benchmarks, the “good” one, which is the 25th percentile, that is the weight under which the lightest quarter of pages sit, and the median. The median comes from the Web Almanac 2024, Sustainability chapter, which gives the median weight of each technology, separately on phone and on computer. Grammage averages these medians over the technologies of the category, weighting each by its number of pages, which gives for example 2,688 KB for showcase on phone. The 25th percentile is then deduced from this median, by multiplying it by the ratio that the Web Almanac 2025, Page Weight chapter, gives between the 25th percentile and the median of the home pages of the whole web, that is 0.497 on phone and 0.507 on computer. The “good” benchmark is therefore about half the median, with 1,336 KB for showcase on phone.
| Category | Phone, 25th percentile | Phone, median | Computer, 25th percentile | Computer, median |
|---|---|---|---|---|
| Presentation | 699 KB | 1,406 KB | 752 KB | 1,484 KB |
| Documentation | 495 KB | 997 KB | 439 KB | 865 KB |
| Showcase | 1,336 KB | 2,688 KB | 1,508 KB | 2,976 KB |
| Editorial | 1,330 KB | 2,675 KB | 1,490 KB | 2,939 KB |
| E-commerce | 1,480 KB | 2,977 KB | 1,645 KB | 3,246 KB |
| Application | 1,154 KB | 2,321 KB | 1,307 KB | 2,578 KB |
The request benchmarks come from the Web Almanac 2025, Page Weight chapter, and those for the DOM from the Web Almanac 2024, Markup chapter. The former depend on the type of page, the home page when the address is the root and an inner page otherwise, the latter only on the device, and neither changes with the category.
| Category | Phone, 25th percentile | Phone, median | Computer, 25th percentile | Computer, median |
|---|---|---|---|---|
| Requests, home page | 43 | 75 | 47 | 80 |
| Requests, inner page | 41 | 68 | 45 | 73 |
| DOM elements | 342 | 594 | 353 | 621 |
The same technology can feed two categories, WordPress, Drupal and Joomla for showcase and editorial, Gatsby for presentation and application, which explains why showcase and editorial have almost identical weight benchmarks.
A curve set by two benchmarks
For weight, requests and the DOM, Grammage places the page on a log-normal curve, the same as Lighthouse, set by two real benchmarks of the category. A page as light as the lightest quarter of pages, the 25th percentile, gets 0.9, a page in the average, that is at the median, gets 0.5, and the score slides gently between the two and beyond, with no staircase step. A page as far above the median as the good benchmark is below it gets 0.1, which comes down to about twice the median, and an almost empty page approaches 1 without ever exceeding it.
z = ln(measure / median) × 0.9062 / ln(median / good)
score = erfc(z) / 2
good the “good” benchmark, the 25th percentile of the category
median the “median” benchmark of the category
erfc the complementary error function
0.9062 the value that gives 0.9 to the page equal to the “good” benchmarkFrom benchmarks to letters
The letter thresholds are the points where this curve crosses real benchmarks. An A starts at 90, the score of the “good” benchmark, so at the level of the lightest quarter of pages. A C starts at 50, the score of the median, and an E at 10, the score of a page about twice as heavy as the median, then below 10 the page gets an F. Between these three benchmarks, a B starts at 70 and a D at 30, which cut in half the score gap between two neighbouring benchmarks. Take the weight of a showcase page on phone, whose median is 2,688 KB and whose “good” benchmark is 1,336 KB, and look at which weight the curve gives each threshold.
| Weight score | Letter | Weight | Benchmark |
|---|---|---|---|
| 90 | A | 1,336 KB | the “good” benchmark, the 25th percentile |
| 70 | B | 2,020 KB | between the “good” benchmark and the median |
| 50 | C | 2,688 KB | the median |
| 30 | D | 3,578 KB | between the median and the last benchmark |
| 10 | E | 5,407 KB | about twice the median, 2.01 times |
These weights are read on the score of the weight alone. The score of the page then adds up its five parts, so it reaches 90 only when the page is at the level of the lightest quarter on every criterion, which is what an A means. Requests and the DOM follow the same curve with their own benchmarks, which gives them other thresholds, for example 43 requests for the A and 75 for the C on the home page of a phone.
The score out of 100
The score goes from 0 to 100 and compares the page with those of its category, which the previous section explains. It adds up five parts, with the following weights.
The five parts
- 30pointsWeightThe bytes the page makes the browser download.
- 30pointsGood practicesFifteen rules checked one by one.
- 15pointsRequestsEvery file requested from the server.
- 15pointsThe DOMThe number of elements on the page.
- 10pointsHostingA green or low-carbon server.
Each part receives a score between 0 and 1, which is multiplied by its weight, and the score of the page is the sum of these points divided by the weights counted only, then rounded to the nearest integer, with halves going to the even integer. These weights are a choice of method, which we publish. Weight wins out because it is the quantity that the carbon model multiplies, requests and the DOM each count for half as much, good practices catch what neither the weight nor the count sees, and hosting weighs less than what the page makes thousands of visitors download. Weight, requests and the DOM are those of the initial load, before scrolling.
Good practices and hosting
The good practices part is the sum of the weights of the rules that pass, a rule that is half followed counting for half, divided by the sum of the weights of the rules that apply to the page, and the full list is in the next section. The hosting part is 1 when the Green Web Foundation recognises the host as green or when the server is in a country whose electricity emits less than 100 g of CO₂ per kWh, 0 otherwise. When the hosting cannot be known, behind a CDN like Cloudflare that hides the real server, this part leaves the calculation, and the score is computed on 90 points scaled up to 100, because we prefer to say nothing rather than punish a page for something we do not know.
A worked example
On 29 September 2026, the home page of solyzon.com was measured with the phone profile, in the showcase category. The four parts counted earn 28.2, 11.85, 0.75 and 24 points, that is 64.8 out of 90, and 64.8 multiplied by 100 and divided by 90 gives 72, a score of 72 out of 100. Almost everything that is missing comes from the DOM, with twice as many elements as the median.
| Part | Measurement | Showcase benchmarks | Score out of 1 | Points |
|---|---|---|---|---|
| Weight | 1,162 KB on initial load | 1,336 and 2,688 KB | 0.94 | 28.2 out of 30 |
| Requests | 53 | 43 and 75 | 0.79 | 11.85 out of 15 |
| DOM elements | 1,214 | 342 and 594 | 0.05 | 0.75 out of 15 |
| Good practices | 20 points out of 25 | 0.80 | 24 out of 30 | |
| Hosting | unknown, behind Cloudflare | removed | outside the calculation |
The letters
The report and the badge only display the score out of 100, because a letter on its own reads like an official verdict that Grammage has no business giving. The letter is used to place the score on the verification page, next to the Sustainable Web Design scale, and as a threshold in your CI, through GRAMMAGE_FAIL_UNDER.
| Threshold | Score | What it means |
|---|---|---|
| A | 90 to 100 | at the level of the lightest quarter of the pages of its category, on every criterion |
| B | 70 to 89 | between that best quarter and the average page |
| C | 50 to 69 | above the average page of its category |
| D | 30 to 49 | below the average page |
| E | 10 to 29 | clearly heavier than the average |
| F | 0 to 9 | more than twice as heavy as the average page |
The fifteen rules
The rules come from the 115 web eco-design good practices of the Green IT collective, which we identify by their RWEB number, from the general eco-design framework for digital services of Arcep and Arcom, the RGESN 2024, and from the W3C Web Sustainability Guidelines, the WSG, in their December 2025 draft. Each rule is worth 1, 2 or 3 depending on how much it really weighs on the footprint. A rule that passes earns its whole weight, a rule that is half followed, what we call “to watch”, earns half, a failed rule earns nothing at all, and a rule that does not apply to the page, a rule about videos for a page without video for example, leaves the calculation.
| Rule | Weight | Passes when | References |
|---|---|---|---|
text-compression | 3 | at least 95% of text bytes over 1 KB arrive compressed in Brotli, gzip or zstd, and half credit between 90 and 95% | RGESN 6.3, RWEB_0076, WSG 5.3 |
static-cache | 2 | every image, font, stylesheet, script or media file has a cache duration, half credit when the browser can only guess it | RGESN 6.2, RWEB_0075, WSG 5.2 |
http2 | 1 | no resource still goes through HTTP/1 | RWEB_0083, WSG 5.12 |
redirects | 2 | one redirect at most | RWEB_0112, WSG 5.4 |
http-errors | 2 | no request answers with an error, a 404 or a 500 for example | WSG 5.4 |
domains | 1 | five domains at most | RGESN 6.7, RWEB_0082, WSG 3.5 |
no-polling | 2 | no address is requested twice during the three seconds of observation | WSG 5.11 |
image-formats | 3 | more than three raster images out of four are in WebP or AVIF | RGESN 5.1, WSG 4.9 |
image-resized | 2 | no image is more than twice as wide as its display, screen density included | RGESN 6.4, WSG 4.9 |
image-lazy | 2 | every image outside the first screen has loading="lazy" | RGESN 6.5, RWEB_0051, WSG 4.9 |
font-families | 2 | two font families at most | RGESN 4.8, RWEB_0032, WSG 4.12 |
font-woff2 | 1 | every font is served as WOFF2 | WSG 4.12 |
no-autoplay | 3 | no video or sound starts by itself | RGESN 4.1, RWEB_0106, WSG 4.9 |
no-infinite-animation | 1 | no endless animation is still running at the end of the measurement | RGESN 4.1, RWEB_0009, WSG 4.10 |
meta-description | 1 | the page has a description, which avoids repeated searches | RWEB_0011, WSG 3.8 |
Vector images, the SVGs, are left out of the resizing and lazy loading rules, since a vector drawing is drawn at any size without weighing more, but their bytes are still counted in the weight of the page like those of any other resource. For fonts, font-families only counts those that are downloaded, the local() fallbacks do not enter into it. The RGESN references point to eight criteria of the framework, which the report uses in an eco-design declaration aid.
What each fix would bring
Each good practice that is not met comes with its fix and with the gain you can expect from it on every view, so that you start with what really weighs. This gain is computed on the real weight of the offending files, recorded during the measurement, to which we apply a deliberately cautious share, drawn from published studies rather than from the best case, then it is translated into carbon by the same model as everything else, with the same host.
bytes saved = sum, over each offending file, of bytes transferred × share
carbon saved = Sustainable Web Design v4 applied to the bytes saved
oversized image share = 1 − (useful width / real width)²
useful width = min(real width, displayed width × screen density)| Fix | Share saved | Where the share comes from |
|---|---|---|
| Images in WebP or AVIF | 30% | Google study on WebP, 25 to 34% smaller than JPEG at equal quality |
| Images at their size | the surplus area | direct calculation, displayed width times screen density, compared with the real width |
| Text compression | 70% | gzip and Brotli most often remove 60 to 80% of a text file |
| Fonts in WOFF2 | 30% | W3C evaluation, WOFF2 about 30% lighter than WOFF |
| No autoplay | the whole media | a media that only starts on click is not loaded |
For images that are too large, we do not take a fixed share but the surplus area, since an image twice too wide in each direction carries four times the useful pixels, and we compute it with the width it has on screen, multiplied by the density of the simulated screen. The other good practices, a missing description or too many domains for example, have no gain that can be put in bytes, and the report does not invent one. The report also replays the score with the fix applied, on the initial load, to say how many points it would bring, and this is what allows the advice to be ranked.
What validates the method
A published method is only worth something if its figures can be reproduced and agree with what others measure, so we checked three things, that the measurement repeats, that the benchmarks hold up against real pages, and that our way of measuring finds the same as other tools.
The measurement is reproducible
On 29 September 2026, we measured eight sites three times during the night, with the phone profile, on an Apple M4 Pro with Chromium 153 and Playwright 1.63, through three successive versions of the engine that share the same protocol. Each cell gives the three values in order.
| Site | Weight, KB | Requests | DOM | Computing time, s |
|---|---|---|---|---|
| solyzon.com | 1,585, 1,585, 1,586 | 66, 66, 66 | 1,215, 1,215, 1,215 | 24.1, 22.6, 28.7 |
| zetelecom.fr | 17,310, 17,309, 17,309 | 168, 167, 167 | 1,285, 1,285, 1,285 | 4.2, 4.6, 9.1 |
| kmc-events.fr | 2,018, 2,431, 2,394 | 47, 53, 53 | 474, 477, 477 | 1.7, 9.9, 4.8 |
| isepeat.fr | 1,013, 1,016, 1,017 | 39, 39, 39 | 409, 409, 409 | 1.3, 4.3, 2.7 |
| apportr.com | 650, 651, 651 | 28, 28, 28 | 766, 766, 766 | 18.0, 26.9, 26.7 |
| www.websitecarbon.com | 162, 162, 162 | 21, 21, 21 | 228, 228, 228 | 0.4, 0.8, 0.3 |
| www.ecoindex.fr | 137, 137, 137 | 5, 5, 5 | 195, 195, 195 | 0.1, 0.2, 0.1 |
| digitalbeacon.co | 83, 83, 83 | 12, 12, 12 | 60, 60, 60 | 0.1, 0.3, 0.1 |
Weight, requests and the DOM repeat within 0.6% on seven sites, the largest gap being one more request out of 167 for zetelecom.fr. The only exception is kmc-events.fr, whose page changes by itself from one load to the next. Computing time varies from simple to double and up to almost six times for kmc-events.fr, which explains why it is shown but not scored. A measurement made from the CI Docker image also gives the same figures as one made on a workstation, 1,584 KB, 66 requests and 1,215 elements for solyzon.com in both cases, within one kilobyte.
The benchmarks against real pages
During the night of 29 to 30 September 2026, we measured one hundred and eighty home pages, thirty per category, mostly French and European, with a single pass per page, four pages at a time and the category of each list declared. The table compares the measured initial weight with the Web Almanac benchmarks.
| Category | Pages measured | Measured 25th percentile | Measured median | Median score |
|---|---|---|---|---|
| Presentation | 30 out of 30 | 469 KB, 33% below the benchmark | 891 KB, 37% below the benchmark | 66 |
| Documentation | 30 out of 30 | 359 KB, 27% below the benchmark | 665 KB, 33% below the benchmark | 63.5 |
| Showcase | 28 out of 30 | 1,150 KB, 14% below the benchmark | 2,260 KB, 16% below the benchmark | 51 |
| Editorial | 24 out of 30 | 1,526 KB, 15% above | 1,980 KB, 26% below the benchmark | 51.5 |
| E-commerce | 18 out of 30 | 2,667 KB, 80% above | 3,484 KB, 17% above | 38 |
| Application | 27 out of 30 | 1,064 KB, 8% below the benchmark | 3,105 KB, 34% above | 52 |
Showcase, editorial and application hold their benchmarks, with a median score between 51 and 52 whereas the average page of a category gets 50. Presentation and documentation measure about 30% less than the Web Almanac, but our corpus there is made mostly of tool sites for developers, probably more frugal than average, so this gap says something about the corpus rather than about the benchmarks. E-commerce is the least reliable category, because twelve shops out of thirty refused the measuring browser and the remaining eighteen are mostly large retailers, which does not allow a conclusion. A modified benchmark changes scores already published, and this comparison did not modify any.
Against other tools
The same day, we read the latest public results of EcoIndex and Digital Beacon on seventeen pages, without relaunching anything on their side. When ecoindex.fr tested the page recently, the EcoIndex that Grammage computes on its own measurement falls exactly on theirs, and the gaps come from old results or from pages whose content moves from one day to the next.
| Page | Grammage | ecoindex.fr | ecoindex.fr test |
|---|---|---|---|
| www.greenit.fr | 63 | 63 | 7 July 2026 |
| www.ademe.fr | 59 | 59 | 15 April 2025 |
| www.service-public.fr | 45 | 45 | 22 September 2026 |
| astro.build | 51 | 51 | 24 April 2026 |
| www.francetvinfo.fr | 11 | 11 | 14 September 2026 |
| fr.vuejs.org | 52 | 57 | 25 January 2023 |
| www.lemonde.fr | 8 | 18 | 24 September 2026 |
Digital Beacon goes through PageSpeed Insights, so through Lighthouse, which does not scroll the page, and it weighs about the same the pages that load nothing while scrolling. On a page that loads while scrolling, it stays at the initial load and is far from the whole page.
| Page | Grammage, initial | Digital Beacon | Grammage, whole page |
|---|---|---|---|
| gohugo.io | 441 KB | 448 KB | 441 KB |
| astro.build | 340 KB | 334 KB | 469 KB |
| www.doctolib.fr | 7,291 KB | 6.93 MB | 7,291 KB |
| www.lemonde.fr | 1,808 KB | 1.03 MB | 10,138 KB |
Digital Beacon’s grams are on the other hand two to three times higher than ours for the same weight, 0.164 g against 0.07 g for gohugo.io, because it still applies the former Sustainable Web Design v3 model, which counted much more energy per byte than v4. The three tools rank the pages in the same order, docs.python.org first, doctolib.fr and framasoft.org last, but they differ on the letter, because they do not ask the same question. EcoIndex judges the whole page in absolute terms, on quantiles fixed since 2016, Digital Beacon judges the grams on the Sustainable Web Design scale, and Grammage judges the initial load against the pages of the same category.
The limits of the measure
It is not an energy measurement. Carbon is an estimate based on a model, which takes bytes as an indicator of energy without measuring the processor or the memory of the device, and its own authors consider it poorly suited to spotting what should be optimised in a page. Two pages of the same weight therefore get the same estimate, even if one makes the phone work much harder. The authors also do not publish a quantified margin of error, and their sources differ a lot from one another.
The server remains partly invisible. Grammage does not see what the server does to build the page, and behind a CDN, that is a network of relay servers, it does not even know where the origin server is, so it leaves it unknown rather than guess. Six of the eight sites of our September 2026 campaign went through Cloudflare, for which the Green Web Foundation answers in place of the real host, whereas Website Carbon counts them as green, which takes 18% off its figure.
The carbon of the whole page assumes that a visitor scrolls to the bottom, which probably overestimates long pages, such as those of media sites. And the return visit, measured from 0% to 10.3% of the first load depending on the site, is not deducted from the main figure.
Computing time is not scored, because it still varies from simple to double from one measurement to the next. The network is not throttled during the measurement, which does not change the bytes counted but can change what a page decides to load depending on the speed of the connection. A page that changes by itself, with randomly drawn content or ads, does not weigh the same at each visit, and the median of three passes only erases part of this gap.
The benchmarks come from the Web Almanac, that is from real sites, and not from a target. A page that holds the median of its category gets 50, which does not say it is frugal. And a page protected by an anti-robot service cannot be measured at all.
The versions
Each report carries three versions, the one of Grammage, the one of the measurement protocol and the one of the scoring method. The protocol only changes if what is measured changes, and the scoring changes when the benchmarks, the weights, the reference data or what is compared change. Two scores can only be compared if they share the same protocol and the same method, and an old report always keeps the letter and the benchmarks of the method it names, in its score.method field.
| Version | What distinguishes it |
|---|---|
grammage-1 | the measurement protocol, which only changes if what is measured changes |
notation-2026.3 | six letters specific to Grammage, each threshold of which falls on a real benchmark of the category |
The sources
Each figure on this page comes from one of these sources, from a measurement that Grammage made itself or from a calculation that can be redone from them. The country of a server is deduced from its IP address by RIPEstat, and the intensity data are those that CO2.js embeds.
- Sustainable Web Design, emissions estimation model
- Sustainable Web Design, carbon rating scale
- International Telecommunication Union, Internet traffic in 2022
- Malmodin, 2023, split between use and manufacturing of hardware
- Green Web Foundation, CO2.js and the verification of green hosts
- Electricity Maps, annual electricity intensity methodology
- HTTP Archive, Web Almanac 2024, Sustainability
- HTTP Archive, Web Almanac 2024, Markup
- HTTP Archive, Web Almanac 2025, Page Weight
- Lighthouse, performance scoring calculation
- EcoIndex, published method
- ADEME, Impact CO2, equivalence factors
- Green IT, 115 web eco-design good practices
- Arcep and Arcom, RGESN 2024
- W3C, Web Sustainability Guidelines
- European Union, directive (EU) 2024/825
See what your site really weighs
Grammage brings together in a single tool the audit in a real browser, the code analysis in the CI/CD and a signed result that anyone can verify.
Free trial, no commitment.
Try it for free