The project
CarboneWatch measures what a machine spends on AI services. It does not measure your website. For that, the same agency publishes a free JavaScript library, Carbon Site Kit: it estimates what a page cost to deliver, in the browser of whoever opens it.
The application watches the requests a machine sends to AI services, and estimates their energy and CO₂e. The kit watches the bytes a page moves across the network, and estimates the same thing. Nothing in common in what is observed; the same rule about what is claimed.
Both are estimators, not meters. Neither reads an actual electricity consumption: they apply published factors to observed quantities, and say which ones. The kit follows the Sustainable Web Design Model; the application has its own method, described on this site.
It reads what the browser already knows: the list of resources loaded and their real weight on the network. It writes no cookie and no storage, and sets no identifier — the tally lives in memory and disappears with the tab.
What it does not know, it says, rather than rounding it away. A resource served by another origin that hides its size is counted as unknown, never as zero, and the origin is named next to the figure. A total with three unknowns beats a round total that erased them.
Nothing is sent anywhere until you give it an address. That is a decision separate from installing it, with consequences of its own: aggregating visits means collecting one more piece of data.
The shortest path measures the page and shows the result. It asks for no account, no key and no address to call.
npm install carbone-cost
import { observePage } from "carbone-cost/browser";
import { formatForDisplay, trackPageview } from "carbone-cost";
observePage({
initialRoute: location.pathname,
onMeasure(measurement) {
const event = trackPageview(measurement);
const badge = formatForDisplay(event.result);
document.querySelector("#carbon").textContent =
badge.gramsPerViewRounded + " g CO2e";
}
});
gramsPerViewRounded is the figure to display; category sorts it into three bands, for anyone who prefers a word to a number. Only one collector may run at a time: starting a second one throws, rather than quietly counting everything twice.
A site without a bundler — a WordPress theme, a hand-written page — loads the same code from one tag. The file weighs 6.7 kB minified and exposes one global object.
<script src="https://cdn.jsdelivr.net/npm/@clemsrec/script-tag@0.2.10/dist/carbon-site-kit.min.js"></script>
<script>
var page = window.CarbonSiteKit.trackPageview({ bytesTransferred: 1200000 });
console.log(page.result.gramsCO2e);
</script>
The version number is in the address on purpose. A CDN address without one updates a script nobody reviewed, on every visitor, without warning.
Two limits worth knowing: this build does not measure the page — the collector exists only as a module, so the bytes are yours to provide — and it sends nothing until init has been given an address.
The adapter provides the route that receives measurements, for anyone who wants to aggregate them server-side.
// app/api/carbon/route.ts
import { createNextCarbon } from "@clemsrec/next";
const carbon = createNextCarbon();
export async function POST(request) {
return carbon.collectHandler(request);
}
A resource served from cache is counted as the browser reports it: Chromium returns about 300 bytes where other engines return zero. The divergence is surfaced rather than corrected — subtracting an invented constant would become a lie the day Chromium changes it.
A back navigation restored from the browser cache costs nothing: no resource is reloaded. That is correct, and it looks like a breakage.
A prefetched page is billed to the page that triggered it. Frameworks fetch what comes next when a link is hovered, before the address changes: arriving somewhere can therefore show almost zero while the previous page carries the weight. That is the honest accounting, and it surprises people.
The packages are ES modules only: a require() will fail. They are on 0.x, and their interface can still move between minor versions.
Published on npm, MIT licensed.
| carbone-cost | The core: estimation, the page collector in carbone-cost/browser and the React badge in carbone-cost/react. This is the one to install first. |
| @clemsrec/browser | The browser SDK, which sends measurements to an address you host. |
| @clemsrec/script-tag | The same one, as a single file and a global object, for sites with no build. |
| @clemsrec/next | The Next.js adapter, for the route that receives. |
Version numbers are on npm: they move faster than this page.