Introduction

SAP (Sustainable AI Protocol) is an open protocol for measuring AI usage across applications. It provides a standard way to capture, store, and aggregate telemetry data — tokens, estimated energy, and carbon — for every AI inference.

Think of it like analytics for AI usage. Every time your application calls an AI model, SAP records what happened: which model, how many tokens, and what that costs in estimated energy. The data aggregates into personal stats (per user) and global stats (across all integrations).

SAP is currently tracking real AI usage in production across the PHEWSH ecosystem, with support for external integrations. Optionally, it exposes usage to end users via a small UI component — sometimes called "the missing button" in AI interfaces.

Personal stats are scoped to a user or session. Global stats aggregate all events across all integrations.

What it does

What it does not do

Honest about estimates. SAP uses model-based estimates derived from published research, not direct measurement from data centers. No AI provider currently exposes per-request energy data. SAP is designed for increasing fidelity — estimates today, verified telemetry when infrastructure providers publish real numbers.

Why integrate SAP

Quick start

The simplest integration is a single API call after each AI inference. This example uses the Supabase RPC endpoint that SAP runs on:

// After your AI call completes, fire and forget:
fetch('https://fpnpfnahwaztdlxuayyv.supabase.co/rest/v1/rpc/track_sap_event', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'apikey': YOUR_SUPABASE_ANON_KEY,
    'Authorization': `Bearer ${YOUR_SUPABASE_ANON_KEY}`
  },
  body: JSON.stringify({
    p_source: 'external',
    p_model: 'anthropic/claude-sonnet-4',
    p_prompt_tokens: 450,
    p_completion_tokens: 820,
    p_kwh: 0.00076,
    p_co2_g: 0.38,
    p_water_ml: 1.37
  })
});

That's it. One call per inference. The call is designed to be fire-and-forget and should never block your application or user experience. The backend atomically updates global, daily, and hourly rollups. No additional setup required.

If you don't want to calculate energy estimates yourself, you can omit p_kwh, p_co2_g, and p_water_ml — the database function uses sensible defaults (0.0004 kWh, 0.2g CO₂, 0.72 mL water).

Event schema

Each AI inference produces one row in the sap_events table:

ColumnTypeDescription
idUUIDAuto-generated primary key
user_idUUIDAuthenticated user (optional, null for anonymous)
session_idTEXTClient-generated session ID (per tab or per session, used to group related interactions)
sourceTEXTintent | cli | styletree | external
modelTEXTFull model slug (e.g. anthropic/claude-sonnet-4)
prompt_tokensINTEGERInput token count
completion_tokensINTEGEROutput token count
estimated_kwhDECIMALEstimated energy (kilowatt-hours)
estimated_co2_gDECIMALEstimated CO₂ (grams)
estimated_water_mlDECIMALEstimated cooling water (milliliters)
created_atTIMESTAMPTZEvent timestamp

Privacy. No prompt content is captured. Only metadata: which model, how many tokens, when. Events are anonymous by default — user attribution only happens when the user is explicitly authenticated.

API

SAP uses Supabase RPC and REST endpoints.

Track an event

POST /rest/v1/rpc/track_sap_event

Records a single inference event and atomically updates all aggregation tables. Returns the event UUID.

ParameterTypeRequiredDescription
p_user_idUUIDNoAuthenticated user ID
p_session_idTEXTNoClient session ID
p_sourceTEXTNoApp identifier (default: intent)
p_modelTEXTNoModel slug
p_prompt_tokensINTEGERNoInput tokens
p_completion_tokensINTEGERNoOutput tokens
p_kwhDECIMALNoEnergy estimate (default: 0.0004)
p_co2_gDECIMALNoCO₂ estimate (default: 0.2)
p_water_mlDECIMALNoWater estimate (default: 0.72)

Headers required: apikey (Supabase anon key), Authorization: Bearer {key}, Content-Type: application/json.

Read global stats

GET /rest/v1/global_stats?select=*&id=eq.1

Returns a single row: total_count, total_kwh, total_co2, total_water, sap_tracked_count.

Read personal stats

GET /rest/v1/sap_my_stats?select=*&user_id=eq.{id}

Requires user JWT. Returns: total_events, total_kwh, total_co2_g, total_water_ml, per-source breakdown, avg_tokens, date range.

Energy estimates

SAP uses model-specific coefficients to estimate energy per inference. These are based on published benchmarks (Patterson et al. 2021, ML CO2 Impact, MLCommons estimates) and are conservative.

Model coefficients

Base kWh per ~1000-token inference:

ModelkWh
google/gemini-flash0.00020
anthropic/claude-3-haiku0.00025
deepseek/deepseek-chat0.00030
moonshotai/kimi-k20.00040
anthropic/claude-sonnet-40.00060
anthropic/claude-opus-40.00200

Scaling

kwh = base_coefficient * clamp(total_tokens / 1000, 0.5, 4.0)

Derived metrics

MetricFormulaSource
CO₂ (grams)kwh * 500US grid average (EPA 2023)
Water (mL)kwh * 1800Data center evaporative cooling estimate

Water estimates represent cooling usage based on evaporative data center systems and are directional, not exact. Not all data centers use evaporative cooling — some use closed-loop or air cooling systems that consume significantly less water.

These are estimates. Actual energy varies by data center, hardware, load, region, and cooling system. No AI provider currently exposes per-request energy or water data. SAP is designed for increasing fidelity — estimates today, verified telemetry when infrastructure providers publish real numbers.

Aggregation

Aggregation is handled entirely server-side. Clients only send events. Every call to track_sap_event atomically updates three aggregation layers:

Personal stats are computed on read via the sap_my_stats view, which aggregates all events for a given user_id with per-source breakdowns.

Backend integration

Backend-only integration is the primary pattern. No UI required. Call the API after each inference.

TypeScript

import { trackSapEvent, estimateKwh } from '@/lib/sap';

// After your AI call:
trackSapEvent({
  userId: user?.id,
  source: 'external',
  model: 'anthropic/claude-sonnet-4',
  promptTokens: 450,
  completionTokens: 820,
});

The trackSapEvent function is fire-and-forget — it calculates energy estimates, sends the event, and never throws. It won't block your application or surface errors to users.

Python

import requests, threading

def track_sap_event(model, prompt_tokens, completion_tokens, source="external"):
    total = prompt_tokens + completion_tokens
    kwh = 0.0004 * max(0.5, min(4, total / 1000))

    def _send():
        try:
            requests.post(
                "https://fpnpfnahwaztdlxuayyv.supabase.co/rest/v1/rpc/track_sap_event",
                json={
                    "p_source": source, "p_model": model,
                    "p_prompt_tokens": prompt_tokens,
                    "p_completion_tokens": completion_tokens,
                    "p_kwh": kwh, "p_co2_g": kwh * 500,
                    "p_water_ml": kwh * 1800,
                },
                headers={
                    "apikey": ANON_KEY,
                    "Authorization": f"Bearer {ANON_KEY}",
                    "Content-Type": "application/json",
                },
                timeout=5,
            )
        except: pass

    threading.Thread(target=_send).start()

Any language

SAP is just a POST to a REST endpoint. Any language that can make HTTP requests can integrate. The pattern is always the same: after your AI call completes, fire off the tracking call in the background.

Frontend integration

For browser-based apps, SAP provides a session tracking module that generates a per-tab session ID, maintains a counter, and lets UI components subscribe to tracking events.

import { getSapSessionCount, onSapTrack } from '@/lib/sap';

const [count, setCount] = useState(getSapSessionCount());

useEffect(() => {
  return onSapTrack((n) => setCount(n));
}, []);

The session ID persists for the lifetime of the browser tab. When a user authenticates, all session activity can be attributed to their account, enabling persistent personal usage tracking over time. Anonymous usage works instantly; login enhances it.

Optional UI

The core of SAP is backend measurement. The UI is optional but encouraged — it gives end users visibility into their AI usage, which most interfaces don't provide. It can be embedded, customized, or omitted entirely depending on the application.

The reference implementation is a small button that sits in the chat interface. It shows a session generation count. Clicking it opens a dashboard popup with personal and global stats. The button spins briefly each time an inference is tracked — a subtle signal that measurement is happening.

This is sometimes called "the missing button" — a piece of UI that arguably should exist in every AI chat interface but currently doesn't.

This is not required for integration. Most apps integrate SAP backend-only. The UI is for apps that want to give users visibility.

Reference UI (optional) — try it
0 interactions tracked

Click "I just prompted AI" to simulate a tracked inference. Click the SAP button to open the dashboard popup — the same experience users would see in a real integration.

For non-React apps, an embeddable script is available:

<!-- Auto-attaches to prompt inputs, adds SAP button -->
<script src="https://phewsh.com/SustainableAiProtocol/sap-embed.js"></script>

Status

Live

In progress

Future


SAP is open source. View on GitHub · Contact · A PHEWSH open standard.

Sustainable AI Protocol

This session
0
interactions
0
kWh
0
g CO₂
0
mL water
Global (all users)
interactions
kWh
g CO₂
mL water
Every AI inference is tracked for model, tokens, and estimated energy. No prompt content is captured. Sign in to PHEWSH to see your personal footprint over time.