Download

The project

Measure your website

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.

Two tools, two measurements

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.

What the library observes

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.

Installing it: a badge, with no server

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.

No build step: one tag

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.

Next.js

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);
}

What to know before trusting the figure

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.

The packages

Published on npm, MIT licensed.

carbone-costThe 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/browserThe browser SDK, which sends measurements to an address you host.
@clemsrec/script-tagThe same one, as a single file and a global object, for sites with no build.
@clemsrec/nextThe Next.js adapter, for the route that receives.

Version numbers are on npm: they move faster than this page.