Product
The attestation
A signed result and a verified badge to display on your site
Contents
From the report to the attestation
An attested measurement never rests on the word of your CI alone. A measurement made by Solyzon, on its own machines, has to confirm your figures, and only that measurement gives rise to the attestation.
Your CI signs its report
After the deployment, the attestation job measures your live site and signs the report with the key of your licence, which proves that it really comes from a licensed Grammage image.
Solyzon draws three pages
A signature does not prove that the figures are true, so Solyzon itself measures the entry page and two other randomly drawn pages again at the time of the measurement, under the same conditions. Since nobody knows in advance which ones will be drawn, all the pages would have to be falsified to cheat.
The figures must hold
Each drawn page must weigh at most 20% more when measured by Solyzon than in your report, on the initial load as well as in total transfer. A lighter page passes, since you gain nothing from it.
The attestation is signed
Solyzon then signs the fingerprint in grams, the weight comparison, the score out of 100, the dates, the tool and the method, and produces the verified report and the attestation as PDFs, signed as well.
Anyone can check it
Your badge checks this signature in each visitor’s browser, and the verification page of your domain publishes the figures, the dates and the documents with their fingerprint.
The attestation remains valid for twelve months. A domain receives at most ten CI verifications per day, which a normal release to production never reaches, and they do not count towards any quota.
Without a CI, on-demand verification
A site without a CI, or hosted elsewhere, can also be attested on demand, once a week per domain. Solyzon then performs the whole audit itself, site discovery included, and since there is no report to compare, its own measurement is published as it is. The pages measured count towards the monthly quota of your licence.
curl -X POST https://api.getgrammage.com/v1/certifications \
-H "Authorization: Bearer $GRAMMAGE_LICENSE" \
-H 'content-type: application/json' \
-d '{"url": "https://example.com/", "scope": "site", "category": "auto"}'| Field | Default | Role |
|---|---|---|
url | required | the starting address, on a domain of your licence |
scope | required | page for a single page, site for the whole site |
category | required | auto, presentation, documentation, showcase, editorial, ecommerce or application |
device | mobile | mobile or desktop |
maxPages | 50 | the cap on the pages of a site, up to 100 |
mode | normal | fast, normal or full, that is 1, 2 or 3 passes per page |
originCountry | the country of the origin server behind a CDN, as a two-letter ISO code |
The response arrives right away as a 202, with the address of the result in the Location header, which you then follow as explained in the API documentation. A request that fails does not block the week, so that you can fix and try again.
The badge
The badge fits on two lines. The first gives the grams of CO₂ per view, and the second compares the weight of the page with that of the sites of its category, in words and with the needle of the gauge, which rises when the badge enters the screen. The higher the needle rises, the lighter the page, and the gauge keeps the colours of the logo, with no green, orange or red, to draw a measured fact rather than a judgement.
measured by Grammage
The badge of a page, large
measured by Grammage
The badge of the whole site, compact and in dark theme
The badge of a page only shows its figures on the measured page, and the site badge only exists with a whole-site result, whose grams are an average per page, weighted by template, since Grammage does not know the traffic of each page. It speaks French, English, German, Spanish, Italian, Dutch and Portuguese, and a click on it always leads to the verification page of the domain.
Why it cannot lie
The badge reads no figure in your page. It asks the API for the attestation of its own domain, then checks in the browser that it is signed by the Solyzon key, that it does concern this domain and this page, and that it has not expired. The address of the API and the public key are written in the script itself, so a site can neither serve it an older and more flattering attestation, nor copy the one of another site. At the slightest failure, it writes it in the console and displays “N/A” in place of the figures, keeping its shape, which also lets you place and style it before any verification.
The badge ages
The date of the badge says when the page was measured, and the attestation expires after twelve months, so the badge ages in steps. The simplest way to keep it accurate is to let the CI renew it on every release to production, or to take the re-measurement option, which has it measured again every three months.
| Age of the measurement | What the badge shows |
|---|---|
| Under 3 months | the badge is displayed as it is |
| From 3 to 12 months | it keeps its figures and adds a line that says its age, “measured more than 5 months ago” |
| Beyond 12 months | it loses its figures and its needle, and only says “Measurement older than a year, to be renewed” |
What the badge is allowed to say
The badge carries no grade, no leaf, and no word like “eco-friendly” or “responsible”, and that is deliberate. European directive 2024/825 indeed forbids general environmental claims, and a figure claim must remain accurate and verifiable, which a dated, estimated measurement that names its method makes possible. This is also why nothing is ever said about a whole site from a single page.
Place the badge
The badge is a single JavaScript module, a <grammage-badge> element written without any dependency, which you load from the API rather than install through npm. It therefore updates itself, and it works the same way in all frameworks, where only the way of loading the script changes. It only asks for its attestation when it gets close to the screen, so a badge placed in the footer costs nothing to a visitor who does not scroll down that far.
- HTML
- WordPress
- Nuxt
- Vue
- Next.js
- Astro
- Svelte
- Angular
<script type="module" src="https://api.getgrammage.com/v1/badge.js"></script>
<grammage-badge site="example.com"></grammage-badge><?php
add_action('wp_enqueue_scripts', function () {
wp_enqueue_script_module('grammage-badge', 'https://api.getgrammage.com/v1/badge.js');
});<template>
<grammage-badge site="example.com" />
</template>
<script setup>
useHead({ script: [{ src: 'https://api.getgrammage.com/v1/badge.js', type: 'module' }] });
</script>import Script from 'next/script';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<grammage-badge site="example.com" />
</body>
<Script src="https://api.getgrammage.com/v1/badge.js" type="module" />
</html>
);
}<script is:inline type="module" src="https://api.getgrammage.com/v1/badge.js"></script>
<grammage-badge site="example.com"></grammage-badge>Vue and Nuxt have to be told, in the compiler configuration, that the element is not one of their components, and Angular declares schemas: [CUSTOM_ELEMENTS_SCHEMA] in the component that carries the badge. Svelte and React 19 accept the element as it is.
export default defineNuxtConfig({
vue: { compilerOptions: { isCustomElement: (tag) => tag === 'grammage-badge' } },
});Adapt it to your site
| Attribute | Role |
|---|---|
site | the verified domain, without https://, for the site badge |
page | the path of the verified page, /pricing for example, for the badge of a page |
lang | the language, otherwise the one of the page, then the one of the browser |
size | m for the large size, compact by default |
theme | light or dark to force the theme, which otherwise follows the color-scheme of the place where it is set |
align | right to align the “measured by Grammage” line to the right under the pill, left by default |
The badge can also be tuned with CSS variables set on the element, with your own tokens, and they override its default values.
grammage-badge {
--grammage-surface: var(--color-paper);
--grammage-text: var(--color-ink);
}| Variable | Role |
|---|---|
--grammage-surface | the background of the pill |
--grammage-text | the text of the pill |
--grammage-frame | the outline of the gauge |
--grammage-low | the light part of the gauge |
--grammage-high | the dark part of the gauge |
--grammage-caption | the “measured by Grammage” line, under the pill |
--grammage-radius | the rounding of the pill |
--grammage-font | the font, Inter then the system one |
CSP and privacy
A site that sets a Content-Security-Policy must allow the API in two directives, to load the module and to read the attestation.
script-src 'self' https://api.getgrammage.com
connect-src 'self' https://api.getgrammage.comThe badge sets no cookie, and the API does not keep the IP address of visitors, which it only counts per minute and per status. Cloudflare, which protects the API, does see every request go by, however, and it is up to you to mention it among your processors if you keep a list of them. You can reuse this sentence in your privacy policy.
The Grammage badge displayed on this site asks api.getgrammage.com, the Solyzon service that measured the site, for the result of that measurement, at the moment it appears on the screen. This request sets no cookie, and the Solyzon API does not record the address of your device. It goes through Cloudflare, which protects this service.
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