How To Build a Carbon-Aware Website Using React and Next.js

EcoPing.earth demo of a carbon aware website (note: this is the author’s website).
Grid and Carbon Intensity for Web Developers
Carbon intensity refers to the amount of carbon dioxide (CO₂) emitted to produce a kilowatt-hour (kWh) of electricity. It varies significantly by region, depending on the sources of power available. A low carbon intensity is considered to be below 50 grams of CO₂ per kWh, while coal-reliant countries, like Poland, can reach levels as high as 600 grams per kWh. Different countries produce different amounts of electricity from different sources. Some of it is green and renewable (low intensity) and some is produced using fossil fuels (high intensity).
Electricity Maps visualization of electricity from different sources, per country.
Why Carbon Awareness Matters in Web Design
Did you know that approximately 54% of a website’s carbon emissions come from the end-user’s device? That’s a significant portion of a site’s impact that can be managed by adjusting the experience based on grid conditions.
Image from Electricity Maps.
Make a Carbon-Aware Website Using React and Next.js
We can make a carbon-aware website in three simple steps, by harnessing the power of server-side rendering on Next.js. Assuming you’ve installed Next.js with the App Router, firstly signup at carbonaware.cloud to get your API keys. It’s a free service and we’re going to be using therequestInfo endpoint.
Secondly, we’ll create a server-side function to fetch the live grid data, using the code below. We use the CarbonAwareAPI for this. It’s nice and clever and will do the IP fetch from our request headers, so that we can find the client’s country code (we need the country code to find the current live grid intensity). Once we have that, we can pass it back to our components on the front end.
// src/app/actions.ts
"use server";
import { headers } from "next/headers";
import CarbonAwareAPI, {
pickHeaders,
allowedHeaders,
} from "@fikastudio/carbonaware";
// Get API key from https://carbonaware.cloud/
const client = new CarbonAwareAPI(
process.env.CARBONAWARE_ACCESS_TOKEN!,
process.env.CARBONAWARE_SECRET_TOKEN!
);
export const fetchCarbonIntensity = async (): Promise<number> => {
try {
// Fetch the headers for the IP/Client country code
const hdrs = await headers();
// The CarbonAwareAPI is clever and will get the client country from this
// This will return a live grid intensity for the client
const resp = await client.requestInfo({
headers: pickHeaders(hdrs, allowedHeaders.fly),
remoteAddr: hdrs.get("fly-client-ip") || ''
});
return resp.intensity
} catch (error) {
// Default back to the global average
return resp.globalIntensity;
}
};
// /src/app/page.tsx
export default async function Home() {
const intensity = await fetchCarbonIntensity();
const isLowIntensity = intensity < 100
const isMedIntensity = intensity > 100 && intensity < 300
if (isLowIntensity) {
return (
<div>
<h1>Low intensity view</h1>
<img src="my-eco-hosting.jpg" alt="hi-intensity hi-res image" width="1000" />
</div>
);
}
if (isMedIntensity) {
return
<div>
<h1>Medium intensity view</h1>
<img src="my-eco-hosting.jpg" alt="med-res image" width="1000" />
</div>
}
return (
<div>
<h1>High intensity view</h1>
<p>No image to show</p>
</div>
)
}
- Change theme: We can change the site colours.
- Minimize Features: Cut down on non-essential content and animations, focusing only on core information.
- Use System Fonts: Replace custom fonts with system defaults, reducing data transfer and load times.
- Optimize Images or Show Text Alternatives: Reduce image quality, serve lower-resolution images, or replace images with text-based alternatives to save bandwidth.
- Video: Remove the video and show text if the grid is too high. If the grid has lots of renewables, feel free to add an auto-play video (if you need it).
- Carbon budgets: We can limit the amount of content shown on the site based on grid intensity. The more renewable, the more content the user can view.