CLAUDE LABJP
SLACK — Claude Tag rolls out to teams on Slack: tag @Claude into channels to delegate tasks and connect tools, data, and codebasesMODEL — The Opus class gets an upgrade, with stronger coding, agentic, and professional work plus consistency for long-running tasksCODE — Claude Code adds dynamic workflows in research preview, letting Claude break complex work into steps on its ownCODE — The new ultracode setting raises effort to xhigh while letting Claude decide when to use a workflowSECURITY — Anthropic says operators linked to Alibaba's Qwen lab tried to access Claude via thousands of fraudulent accountsLINEUP — Opus 4.8, Sonnet 4.6, and Haiku 4.5 lead the lineup; pick the right one per taskSLACK — Claude Tag rolls out to teams on Slack: tag @Claude into channels to delegate tasks and connect tools, data, and codebasesMODEL — The Opus class gets an upgrade, with stronger coding, agentic, and professional work plus consistency for long-running tasksCODE — Claude Code adds dynamic workflows in research preview, letting Claude break complex work into steps on its ownCODE — The new ultracode setting raises effort to xhigh while letting Claude decide when to use a workflowSECURITY — Anthropic says operators linked to Alibaba's Qwen lab tried to access Claude via thousands of fraudulent accountsLINEUP — Opus 4.8, Sonnet 4.6, and Haiku 4.5 lead the lineup; pick the right one per task
Articles/Claude Code
Claude Code/2026-06-26Intermediate

We Collected Plenty of Claude Code Usage Data — Then Budgeting Still Didn't Work. Field Notes on Cost Attribution and Idle Seats

The Claude Code Analytics API gives you data, but data alone doesn't run a budget. Here are field notes on turning raw usage logs into cost attribution, idle-seat detection, and alerts that don't cry wolf — with working code and the thresholds we actually use.

claude-code123analytics3costmonitoring7teambudget2

Premium Article

The data was there, but the meeting couldn't use it

When we rolled out the Claude Code Analytics API, the first thing I built was a dashboard of daily token consumption and cost. The numbers came out cleanly. But every monthly budget meeting stalled on the same question: "This figure — which work did it pay for?"

You can see per-seat consumption. The trouble is that seats and work aren't one-to-one. One person spans several repositories, spends one week firefighting an incident and the next writing a feature in a sprint. Per-seat numbers answer "who used it"; what budgeting actually wants to know is "what it was used on." Running several apps and blogs in parallel as an indie developer myself, I'd already learned that cost has to be tied to work, not to people, before it becomes something you can act on.

This article walks through the three stages it took to turn the API's raw data into something usable in a budget meeting — attributing cost to workstreams, detecting idle seats, and building alerts that don't go stale — with the code we actually run. The focus isn't setup; it's the part where you get stuck after the data is already flowing.

First, pin down the granularity of the raw data

The Analytics API returns metrics per day. The first job is to understand exactly what granularity comes back. Get vague here and every downstream cost attribution drifts.

import os
import httpx
 
BASE = "https://api.anthropic.com/v1/organizations/usage_report/claude_code"
 
def fetch_daily(starting_at: str, ending_at: str) -> list[dict]:
    """Fetch daily Claude Code usage records.
    Note: one record = one day x one user x one model."""
    headers = {
        "x-api-key": os.environ["ANTHROPIC_ADMIN_API_KEY"],
        "anthropic-version": "2023-06-01",
    }
    records, page = [], None
    with httpx.Client(timeout=30) as client:
        while True:
            params = {"starting_at": starting_at, "ending_at": ending_at, "limit": 1000}
            if page:
                params["page"] = page
            r = client.get(BASE, headers=headers, params=params)
            r.raise_for_status()
            body = r.json()
            records.extend(body["data"])
            page = body.get("next_page")
            if not page:
                break
    return records

Two things matter here. First, each record is a "day x user x model" tuple. If the same person uses both Sonnet and Opus on the same day, their single day splits into two records. Aggregate over the wrong key and a mixed-model seat double-counts or quietly drops cost.

Second, always page all the way through. A larger limit won't return everything; you have to loop until next_page is null. On a large team near month-end, skipping this silently loses a few days of data. I missed this early on and once argued a budget off the first-of-month numbers alone — and was wrong.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
An aggregation that attributes cost to workstreams instead of seats, and why that framing changes the conversation
Idle-seat logic that surfaces the seats you pay for but nobody actually uses, every week
A three-part alert threshold (week-over-week, moving average, absolute floor) that stays meaningful instead of going stale
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Claude Code2026-04-29
Observability for Claude Code with OpenTelemetry — A Production-Grade Tracing Guide for Agentic Workflows
Trace Claude Code agent runs end to end with OpenTelemetry. Hook integration, per-tool spans, MCP propagation, cost attribution, and sampling patterns that survive thousands of runs per day.
Claude Code2026-06-25
The Day a Non-Responding MCP Call Swallowed an Entire Unattended Run — Owning the Stop With Your Own Deadline
When a remote MCP tool call stops responding, an unattended scheduled run just keeps waiting. Instead of leaving the cutoff entirely to the platform, here is how I designed my own deadline and a per-connector circuit breaker to own the stop — with working code.
Claude Code2026-06-25
Your Sandbox Can Run the Code but Shouldn't Read Your Credentials — Shrinking the Secret-Read Surface with sandbox.credentials
Claude Code's sandbox can still read ~/.aws/credentials and token env vars by default. Using sandbox.credentials (v2.1.187+), here is how I tightened the secret-read surface of unattended runs at the OS level, with config and verification you can reuse.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →