Anthropic/analytics
Observe Claude Enterprise analytics via the Enterprise Analytics API
(/v1/organizations/analytics/*): seat counts, DAU/WAU/MAU, pending
invites, feature adoption (projects, skills, connectors), and token
cost/usage. Extracts structured seat, adoption, and cost data into
separate versioned resources for CEL queries.
Supports an optional discountRate global arg (fraction, e.g. 0.15 for
"15% off") applied to cost and per-user-usage totals derived from the
Analytics API's list-price amount fields, to reflect enterprise volume
discounts. listCostUsd on per-user rows always stays at list price.
Authentication
Requires an Analytics API key (scope read:analytics) created by the
primary owner in claude.ai. Store in a swamp vault.
Usage
swamp extension pull @webframp/anthropic/analytics
swamp vault create local_encryption anthropic # once, if you have no vault yet
swamp vault put anthropic ANALYTICS_KEY # prompts; never pass the value
swamp model create @webframp/anthropic/analytics claude-analytics \
--global-arg 'analyticsKey=${{ vault.get("anthropic", "ANALYTICS_KEY") }}' \
--global-arg 'discountRate=0.15' # optional; defaults to 0
# Collect analytics
swamp model method run claude-analytics collect_analytics
# With date range
swamp model method run claude-analytics collect_analytics \
--input startDate=2026-06-01 --input endDate=2026-07-01Methods
- collect_analytics — fans out across /summaries, /users, and /cost_report; writes snapshot, seats, adoption, and cost resources
- collect_user_usage — per-user token usage + cost from /user_usage_report and /user_cost_report, grouped by product (Claude Code broken out); optionally filtered to one email. Writes a userUsage resource
- collect_cost_by_model — per-model cost over a window from /cost_report (group_by=model), reporting list vs. paid per model, optional token-type detail, and an ungrouped reconciliation total so group-cap truncation is detectable. Window spans at most 31 days. Writes a costByModel resource
2026.10.21.1
Changed: Documentation only: the analyticsKey global argument description
now says to supply the key as ${{ vault.get("anthropic", "ANALYTICS_KEY") }}
and never as a literal. The README and the registry Quick Start now create the
vault if needed and store the key with the interactive
swamp vault put anthropic ANALYTICS_KEY prompt before creating the model.
Upgrade note: No schema or behavioral changes. The model version moves to 2026.10.21.1 with an identity upgrade.
Global Arguments
| Argument | Type | Description |
|---|---|---|
| analyticsKey | string | Analytics API key (scope read:analytics) from claude.ai. Supply it as ${{ vault.get("anthropic", "ANALYTICS_KEY") }}; never pass the literal key |
| discountRate? | number | Enterprise volume discount off list usage/token pricing, as a fraction |
| Argument | Type | Description |
|---|---|---|
| startDate? | string | Start date (YYYY-MM-DD, UTC, inclusive; no earlier than 2026-01-01). Defaults to 7 days ago. |
| endDate? | string | End date (YYYY-MM-DD, UTC, exclusive). Defaults to today. |
| Argument | Type | Description |
|---|---|---|
| days? | number | Lookback window in days, ending now (mutually redundant with |
| startDate? | string | Start (YYYY-MM-DD, UTC, no earlier than 2026-01-01). Defaults to |
| endDate? | string | End (YYYY-MM-DD, UTC). Defaults to now. |
| email? | string | If set, keep only the user whose actor.email matches (case-insensitive). |
| products? | array | Product filter, e.g. ["claude_code"]. Omit for all products; rows are grouped by product either way. |
| Argument | Type | Description |
|---|---|---|
| startDate | string | Start date (YYYY-MM-DD, UTC, inclusive; no earlier than 2026-01-01) |
| endDate? | string | End date (YYYY-MM-DD, UTC, exclusive). Defaults to today. The |
| models? | array | Optional models[] filter (defaults to all models) |
Resources
2026.10.14.1
Added: The manifest now declares license: Apache-2.0 (SPDX). The registry quality rubric scores a declared license separately from the bundled LICENSE.md.
Upgrade note: Metadata only. No code, schema, or behavioral changes.
2026.10.07.1
Added: collect_cost_by_model method and costByModel resource. Reports
per-model token cost over a window from /analytics/cost_report
(group_by=model): list vs. paid USD per model, discountUsd/discountPct,
optional per-model token-type cost split (groupBy: ["token_type"]), and the
unattributed (model-less, e.g. code-execution) total. Issues a second
ungrouped query for the same window to obtain authoritative totals, so the
per-bucket top-100 group cap becomes detectable via a truncated flag rather
than silently under-reporting. Surfaces the export dataRefreshedAt watermark
and a rangeExceedsWatermark flag so not-yet-final recent months are explicit.
Trusts the API's own post-discount amount and pre-discount list_amount
(does not re-apply discountRate). Window spans at most 31 days (the API max);
call once per month for longer ranges. The resource also carries
totalPaidCents (an exact reconciliation anchor, since per-model USD values are
rounded independently and may not sum to totalPaidUsd), modelsFilter (echoes
any models[] filter — totals are scoped to it when set, not org-wide), and
reconciliationChecked (false when the ungrouped query returns an unexpected
dimensioned shape, in which case truncated is set conservatively). The
watermark comparison uses numeric instants, not string compare, so
non-canonical RFC 3339 timestamps are handled correctly. Additive — existing
resources are unaffected.
2026.09.18.1
Upgrade note: Normalized npm:zod dependency version to 4.6.5 across the
repo. No behavioral changes in this extension.
2026.10.07.1
Added: collect_cost_by_model method and costByModel resource. Reports
per-model token cost over a window from /analytics/cost_report
(group_by=model): list vs. paid USD per model, discountUsd/discountPct,
optional per-model token-type cost split (groupBy: ["token_type"]), and the
unattributed (model-less, e.g. code-execution) total. Issues a second
ungrouped query for the same window to obtain authoritative totals, so the
per-bucket top-100 group cap becomes detectable via a truncated flag rather
than silently under-reporting. Surfaces the export dataRefreshedAt watermark
and a rangeExceedsWatermark flag so not-yet-final recent months are explicit.
Trusts the API's own post-discount amount and pre-discount list_amount
(does not re-apply discountRate). Window spans at most 31 days (the API max);
call once per month for longer ranges. The resource also carries
totalPaidCents (an exact reconciliation anchor, since per-model USD values are
rounded independently and may not sum to totalPaidUsd), modelsFilter (echoes
any models[] filter — totals are scoped to it when set, not org-wide), and
reconciliationChecked (false when the ungrouped query returns an unexpected
dimensioned shape, in which case truncated is set conservatively). The
watermark comparison uses numeric instants, not string compare, so
non-canonical RFC 3339 timestamps are handled correctly. Additive — existing
resources are unaffected.
2026.09.18.1
Upgrade note: Normalized npm:zod dependency version to 4.6.5 across the
repo. No behavioral changes in this extension.
Modified 1 behaviors
2026.09.18.1
Upgrade note: Normalized npm:zod dependency version to 4.6.5 across the
repo. No behavioral changes in this extension.
2026.09.15.1
Changed: Bump zod 4.4.3 → 4.6.5
2026.08.28.1
Changed: Normalized the extension license to Apache-2.0 and corrected the copyright holder to "Sean Escriva". Extensions that previously shipped an MIT LICENSE.md are now Apache-2.0, consistent with the repository root and every other extension. No code or behavioral changes.
Upgrade note: License text only. No API, schema, or runtime behavior changed.
2026.08.26.2
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
2026.08.28.1
Changed: Normalized the extension license to Apache-2.0 and corrected the copyright holder to "Sean Escriva". Extensions that previously shipped an MIT LICENSE.md are now Apache-2.0, consistent with the repository root and every other extension. No code or behavioral changes.
Upgrade note: License text only. No API, schema, or runtime behavior changed.
2026.08.26.2
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
2026.08.26.2
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
2026.08.25.1
Changed: Updated labels for improved extension discoverability. Added cross-cutting category labels (security, observability, finops, infrastructure, networking, compliance, devops, ai, incident-response) where applicable.
updated labels
2026.08.24.1
Added: Output metadata attributes for observability.
durationMs: Method execution duration in milliseconds.collectedBy: Extension name that produced the data.fetchedAt: ISO 8601 timestamp when data was fetched (added to resources that previously lacked it).
2026.08.23.1
Changed: Documentation only — no code changes. Documented collect_user_usage
in the README, which previously had no usage example at all, and added a
## Troubleshooting section explaining the collected: false degrade pattern
shared by the adoption, cost, and userUsage collection paths.
2026.08.21.2
Changed: startDate/endDate on collect_analytics and collect_user_usage
are now validated as well-formed YYYY-MM-DD dates before any request is made.
Previously a malformed date (e.g. "not-a-date" or "2026-13-99") silently
passed the range check — Date parsing of garbage input produces NaN, which
made the "end must be after start" comparison a no-op — and the bad value was
sent straight to the Analytics API, surfacing only as an opaque upstream 400.
Malformed dates now fail fast with a message naming the argument and the value
that was rejected.
2026.08.21.1
Changed: Added descriptions to the previously undocumented fields across
the snapshot, seats, adoption, cost, and userUsage resource schemas
(e.g. total_cents, by_cost_type, collected, byProduct, totals). No
behavioral change.
2026.08.14.1
Added: discountRate global arg (fraction, default 0) applying an
enterprise volume discount to cost figures derived from the Analytics API's
list-price amount fields. Applies to cost.total_cents/total_usd/
by_cost_type and per-user costUsd/totalCostUsd; listCostUsd always
stays at list price so the discount and list reference remain comparable.
Both cost and userUsage resources gain a discountRate field echoing
the rate applied.
Added: totals field on the userUsage resource — grand
inputTokens/outputTokens/totalTokens and per-minute rates across all
returned users, in the shape @webframp/ai-usage's generic provider registry
expects, so this resource can be registered there without a bespoke adapter.
Added: days argument on collect_user_usage (capped at 31, the
Analytics API's max window) as an alternative to startDate, so callers
(including a future @webframp/ai-usage-scan step) can drive the lookback
the same way as the other provider scan methods.
Added: Both collect_analytics and collect_user_usage now reject an
inverted date range (endDate at or before startDate) via a shared
assertRange check, instead of silently sending a backwards window to the
Analytics API — collect_user_usage additionally used this to guard
against a near-zero periodMinutes producing wildly inflated per-minute
rates in totals.
2026.07.18.1
Added: An upgrades array entry (no-op) to analytics.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.
2026.07.14.1
Added: collect_user_usage — per-user token usage and cost, so you can see
who is spending what (and how much of it is Claude Code) rather than only the
org aggregate.
Reads the Enterprise Analytics
/v1/organizations/analytics/user_usage_report(tokens: total / output / uncached-input / cache-read, plus requests) and/user_cost_report(amountandlist_amount, USD minor units → USD), grouped byproductsoclaude_codeis broken out from chat/cowork/etc.Optional
emailfilter keeps just one user (matched onactor.email);productsfilters the surfaces;startDate/endDatebound the window (defaults to the last 30 days; the API caps a window at 31 days).Writes a
userUsageresource (instance = the sanitized email, orall) with a per-userbyProductbreakdown plustotalTokens/totalCostUsd. Reuses the samex-api-key(read:analytics) auth and cursor pagination ascollect_analytics. The two reports are collected independently: if onlyuser_cost_reportfails (common on seat-based plans, where it 403s while the usage report still serves tokens), the token data is retained withcollected: trueandcostUsdleft null —collected: falseonly when both fail. A singleemail-filtered result is keyed by the user's unique id (user-<userId>) so emails that sanitize alike cannot collide.Caveats: with no
emailfilter the resource stores email + name for every org user (admin-only PII — mind shared datastores); and very large orgs can page-truncate (the filter is applied after fetch), so prefer a date-bounded, filtered query for a single user.
Additive: collect_analytics and its snapshot/seats/adoption/cost resources are
unchanged.
2026.07.07.1
Fixed:
collect_analyticscalled a non-existent endpoint (/v1/organizations/analytics, HTTP 404) with the wrong param names (start_date/end_date) and a flat-metrics response shape that never matched the real API. Rewritten against the documented Enterprise Analytics API:/analytics/summaries(seats + DAU/WAU/MAU + pending invites,starting_date/ending_date),/analytics/users(paginated, aggregated into adopter counts), and/analytics/cost_report(paginated, summed by cost type).
Added:
costresource — token cost/usage over the window (usage-based Enterprise plans).- Adoption and cost collection are best-effort: a failure in
/usersor/cost_reportno longer fails the whole run (seat-based plans have no cost data).
Changed:
adoptionnow reports adopter counts (users with ≥1 project/skill/connector), aggregated from/analytics/users— there is no org-level adoption endpoint.- The
snapshotresource writes to therecentinstance (latestis reserved by swamp). Query viadata.latest("claude-analytics", "recent").
2026.07.02.1
Added: Initial release. Enterprise Analytics observation model. Collects raw metrics snapshot and extracts structured seat counts (total, active, pending, DAU/WAU/MAU) and adoption metrics (projects, skills, connectors) into separate versioned r
2026.08.14.1
Added: discountRate global arg (fraction, default 0) applying an
enterprise volume discount to cost figures derived from the Analytics API's
list-price amount fields. Applies to cost.total_cents/total_usd/
by_cost_type and per-user costUsd/totalCostUsd; listCostUsd always
stays at list price so the discount and list reference remain comparable.
Both cost and userUsage resources gain a discountRate field echoing
the rate applied.
Added: totals field on the userUsage resource — grand
inputTokens/outputTokens/totalTokens and per-minute rates across all
returned users, in the shape @webframp/ai-usage's generic provider registry
expects, so this resource can be registered there without a bespoke adapter.
Added: days argument on collect_user_usage (capped at 31, the
Analytics API's max window) as an alternative to startDate, so callers
(including a future @webframp/ai-usage-scan step) can drive the lookback
the same way as the other provider scan methods.
Added: Both collect_analytics and collect_user_usage now reject an
inverted date range (endDate at or before startDate) via a shared
assertRange check, instead of silently sending a backwards window to the
Analytics API — collect_user_usage additionally used this to guard
against a near-zero periodMinutes producing wildly inflated per-minute
rates in totals.
2026.07.18.1
Added: An upgrades array entry (no-op) to analytics.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.
2026.07.14.1
Added: collect_user_usage — per-user token usage and cost, so you can see
who is spending what (and how much of it is Claude Code) rather than only the
org aggregate.
Reads the Enterprise Analytics
/v1/organizations/analytics/user_usage_report(tokens: total / output / uncached-input / cache-read, plus requests) and/user_cost_report(amountandlist_amount, USD minor units → USD), grouped byproductsoclaude_codeis broken out from chat/cowork/etc.Optional
emailfilter keeps just one user (matched onactor.email);productsfilters the surfaces;startDate/endDatebound the window (defaults to the last 30 days; the API caps a window at 31 days).Writes a
userUsageresource (instance = the sanitized email, orall) with a per-userbyProductbreakdown plustotalTokens/totalCostUsd. Reuses the samex-api-key(read:analytics) auth and cursor pagination ascollect_analytics. The two reports are collected independently: if onlyuser_cost_reportfails (common on seat-based plans, where it 403s while the usage report still serves tokens), the token data is retained withcollected: trueandcostUsdleft null —collected: falseonly when both fail. A singleemail-filtered result is keyed by the user's unique id (user-<userId>) so emails that sanitize alike cannot collide.Caveats: with no
emailfilter the resource stores email + name for every org user (admin-only PII — mind shared datastores); and very large orgs can page-truncate (the filter is applied after fetch), so prefer a date-bounded, filtered query for a single user.
Additive: collect_analytics and its snapshot/seats/adoption/cost resources are
unchanged.
2026.07.07.1
Fixed:
collect_analyticscalled a non-existent endpoint (/v1/organizations/analytics, HTTP 404) with the wrong param names (start_date/end_date) and a flat-metrics response shape that never matched the real API. Rewritten against the documented Enterprise Analytics API:/analytics/summaries(seats + DAU/WAU/MAU + pending invites,starting_date/ending_date),/analytics/users(paginated, aggregated into adopter counts), and/analytics/cost_report(paginated, summed by cost type).
Added:
costresource — token cost/usage over the window (usage-based Enterprise plans).- Adoption and cost collection are best-effort: a failure in
/usersor/cost_reportno longer fails the whole run (seat-based plans have no cost data).
Changed:
adoptionnow reports adopter counts (users with ≥1 project/skill/connector), aggregated from/analytics/users— there is no org-level adoption endpoint.- The
snapshotresource writes to therecentinstance (latestis reserved by swamp). Query viadata.latest("claude-analytics", "recent").
2026.07.02.1
Added: Initial release. Enterprise Analytics observation model. Collects raw metrics snapshot and extracts structured seat counts (total, active, pending, DAU/WAU/MAU) and adoption metrics (projects, skills, connectors) into separate versioned resources.
2026.07.18.1
Added: An upgrades array entry (no-op) to analytics.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.
2026.07.14.1
Added: collect_user_usage — per-user token usage and cost, so you can see
who is spending what (and how much of it is Claude Code) rather than only the
org aggregate.
Reads the Enterprise Analytics
/v1/organizations/analytics/user_usage_report(tokens: total / output / uncached-input / cache-read, plus requests) and/user_cost_report(amountandlist_amount, USD minor units → USD), grouped byproductsoclaude_codeis broken out from chat/cowork/etc.Optional
emailfilter keeps just one user (matched onactor.email);productsfilters the surfaces;startDate/endDatebound the window (defaults to the last 30 days; the API caps a window at 31 days).Writes a
userUsageresource (instance = the sanitized email, orall) with a per-userbyProductbreakdown plustotalTokens/totalCostUsd. Reuses the samex-api-key(read:analytics) auth and cursor pagination ascollect_analytics. The two reports are collected independently: if onlyuser_cost_reportfails (common on seat-based plans, where it 403s while the usage report still serves tokens), the token data is retained withcollected: trueandcostUsdleft null —collected: falseonly when both fail. A singleemail-filtered result is keyed by the user's unique id (user-<userId>) so emails that sanitize alike cannot collide.Caveats: with no
emailfilter the resource stores email + name for every org user (admin-only PII — mind shared datastores); and very large orgs can page-truncate (the filter is applied after fetch), so prefer a date-bounded, filtered query for a single user.
Additive: collect_analytics and its snapshot/seats/adoption/cost resources are
unchanged.
2026.07.07.1
Fixed:
collect_analyticscalled a non-existent endpoint (/v1/organizations/analytics, HTTP 404) with the wrong param names (start_date/end_date) and a flat-metrics response shape that never matched the real API. Rewritten against the documented Enterprise Analytics API:/analytics/summaries(seats + DAU/WAU/MAU + pending invites,starting_date/ending_date),/analytics/users(paginated, aggregated into adopter counts), and/analytics/cost_report(paginated, summed by cost type).
Added:
costresource — token cost/usage over the window (usage-based Enterprise plans).- Adoption and cost collection are best-effort: a failure in
/usersor/cost_reportno longer fails the whole run (seat-based plans have no cost data).
Changed:
adoptionnow reports adopter counts (users with ≥1 project/skill/connector), aggregated from/analytics/users— there is no org-level adoption endpoint.- The
snapshotresource writes to therecentinstance (latestis reserved by swamp). Query viadata.latest("claude-analytics", "recent").
2026.07.02.1
Added: Initial release. Enterprise Analytics observation model. Collects raw metrics snapshot and extracts structured seat counts (total, active, pending, DAU/WAU/MAU) and adoption metrics (projects, skills, connectors) into separate versioned resources.
Modified 1 behaviors
2026.07.07.1
Fixed:
collect_analyticscalled a non-existent endpoint (/v1/organizations/analytics, HTTP 404) with the wrong param names (start_date/end_date) and a flat-metrics response shape that never matched the real API. Rewritten against the documented Enterprise Analytics API:/analytics/summaries(seats + DAU/WAU/MAU + pending invites,starting_date/ending_date),/analytics/users(paginated, aggregated into adopter counts), and/analytics/cost_report(paginated, summed by cost type).
Added:
costresource — token cost/usage over the window (usage-based Enterprise plans).- Adoption and cost collection are best-effort: a failure in
/usersor/cost_reportno longer fails the whole run (seat-based plans have no cost data).
Changed:
adoptionnow reports adopter counts (users with ≥1 project/skill/connector), aggregated from/analytics/users— there is no org-level adoption endpoint.- The
snapshotresource writes to therecentinstance (latestis reserved by swamp). Query viadata.latest("claude-analytics", "recent").
2026.07.02.1
Added: Initial release. Enterprise Analytics observation model. Collects raw metrics snapshot and extracts structured seat counts (total, active, pending, DAU/WAU/MAU) and adoption metrics (projects, skills, connectors) into separate versioned resources.
Modified 1 behaviors
2026.07.02.1
Added: Initial release. Enterprise Analytics observation model. Collects raw metrics snapshot and extracts structured seat counts (total, active, pending, DAU/WAU/MAU) and adoption metrics (projects, skills, connectors) into separate versioned resources.
- Has README or module doc2/2earned
- README has a code example1/1earned
- README is substantive1/1earned
- Most symbols documented1/1earned
- No slow types (deprecated)1/1earned
- Dependencies pass trust audit2/2earned
- Has description1/1earned
- Platform support declared (or universal)2/2earned
- License2/2earned
- Verified public repository2/2earned