Claude AI metrics
Port's Claude integration allows you to ingest Claude AI (Enterprise) and Claude Platform usage, cost, and Claude Code analytics metrics into your software catalog.
Deployment modes
The integration runs in one of two deployment modes, controlled by the isClaudeEnterprise configuration option. Each mode targets a different set of Claude API endpoints and requires an API key with a different scope.
| Mode | isClaudeEnterprise | Resources synced | Required API key scope |
|---|---|---|---|
| Claude AI (Enterprise) | true (default) | claude-ai-user-activity, claude-ai-user-usage, claude-ai-user-cost | read:analytics |
| Claude Platform | false | claude-platform-usage-record, claude-platform-cost-record, claude-platform-code-analytics | api:admin |
Use Claude AI (Enterprise) mode to track per-user engagement, token usage, and cost for everyday Claude usage such as the web app and Claude Code. Use Claude Platform mode to track aggregated usage and cost for Claude Platform API consumption, typically used by developers.
When initializePortResources is enabled, the integration creates the default blueprints for both Claude AI and Claude Platform, regardless of the selected mode. Only the resources for the active mode are populated with data.
Prerequisites
- An Anthropic API key for the deployment mode you want to use:
- Claude AI (Enterprise) mode requires an analytics API key with the
read:analyticsscope, minted by a Primary Owner fromclaude.ai/analytics/api-keys. - Claude Platform mode requires an Admin API key with the
api:adminscope and access to the usage and cost reports.
- Claude AI (Enterprise) mode requires an analytics API key with the
- Your Port user role is set to
Admin.
Setup
Choose one of the installation methods below. If you are not sure which option to use, review the installation methods overview.
Configuration
Port integrations use a YAML mapping block to ingest data from the third-party API into Port.
The mapping uses the JQ JSON processor to transform fields and shape incoming Claude data into Port entities.
Default mapping configuration
This is the default mapping configuration for this integration. It maps the Claude AI (Enterprise) resources, which are synced in the default deployment mode:
Default mapping configuration (Click to expand)
resources:
- kind: claude-ai-user-activity
selector:
query: 'true'
timeFrame: 30
port:
entity:
mappings:
identifier: .user.id + "-" + .__date
title: (.user.email_address // .user.id) + " - " + .__date
blueprint: '"claude_ai_user_activity"'
properties:
record_date: .__date + "T00:00:00Z"
user_id: .user.id
email: .user.email_address
chat_conversation_count: (.chat_metrics.distinct_conversation_count // 0)
chat_message_count: (.chat_metrics.message_count // 0)
chat_thinking_message_count: (.chat_metrics.thinking_message_count // 0)
chat_skills_used_count: (.chat_metrics.distinct_skills_used_count // 0)
chat_connectors_used_count: (.chat_metrics.connectors_used_count // 0)
code_session_count: (.claude_code_metrics.core_metrics.distinct_session_count // 0)
code_commit_count: (.claude_code_metrics.core_metrics.commit_count // 0)
code_pull_request_count: (.claude_code_metrics.core_metrics.pull_request_count // 0)
lines_added: (.claude_code_metrics.core_metrics.lines_of_code.added_count // 0)
lines_removed: (.claude_code_metrics.core_metrics.lines_of_code.removed_count // 0)
edit_tool_accepted: (.claude_code_metrics.tool_actions.edit_tool.accepted_count // 0)
edit_tool_rejected: (.claude_code_metrics.tool_actions.edit_tool.rejected_count // 0)
write_tool_accepted: (.claude_code_metrics.tool_actions.write_tool.accepted_count // 0)
write_tool_rejected: (.claude_code_metrics.tool_actions.write_tool.rejected_count // 0)
multi_edit_tool_accepted: (.claude_code_metrics.tool_actions.multi_edit_tool.accepted_count // 0)
multi_edit_tool_rejected: (.claude_code_metrics.tool_actions.multi_edit_tool.rejected_count // 0)
notebook_edit_tool_accepted: (.claude_code_metrics.tool_actions.notebook_edit_tool.accepted_count // 0)
notebook_edit_tool_rejected: (.claude_code_metrics.tool_actions.notebook_edit_tool.rejected_count // 0)
web_search_count: (.web_search_count // 0)
chat_projects_used_count: (.chat_metrics.distinct_projects_used_count // 0)
chat_projects_created_count: (.chat_metrics.distinct_projects_created_count // 0)
chat_artifacts_created_count: (.chat_metrics.distinct_artifacts_created_count // 0)
chat_files_uploaded_count: (.chat_metrics.distinct_files_uploaded_count // 0)
chat_shared_conversations_viewed_count: (.chat_metrics.shared_conversations_viewed_count // 0)
office_session_count: >-
([.office_metrics.excel.distinct_session_count,
.office_metrics.powerpoint.distinct_session_count,
.office_metrics.word.distinct_session_count,
.office_metrics.outlook.distinct_session_count] | map(. // 0) | add)
office_message_count: >-
([.office_metrics.excel.message_count,
.office_metrics.powerpoint.message_count,
.office_metrics.word.message_count,
.office_metrics.outlook.message_count] | map(. // 0) | add)
cowork_session_count: (.cowork_metrics.distinct_session_count // 0)
cowork_message_count: (.cowork_metrics.message_count // 0)
design_session_count: (.design_metrics.distinct_session_count // 0)
design_message_count: (.design_metrics.message_count // 0)
- kind: claude-ai-user-usage
selector:
query: 'true'
startingAt: '2026-01-01T00:00:00Z'
port:
entity:
mappings:
identifier: >-
.actor.user_id + "-" + .__starting_at[:10] + "-" + (.product // "all")
+ "-" + (.model // "all")
title: (.actor.name // .actor.email // .actor.user_id) + " - " + .__starting_at[:10]
blueprint: '"claude_ai_user_usage"'
properties:
record_date: .__starting_at
range_end: .__ending_at
user_id: .actor.user_id
user_name: .actor.name
email: .actor.email
deleted: (.actor.deleted // false)
product: .product
model: .model
context_window: .context_window
inference_geo: .inference_geo
speed: .speed
uncached_input_tokens: (.uncached_input_tokens // 0)
cache_creation_1h_tokens: (.cache_creation.ephemeral_1h_input_tokens // 0)
cache_creation_5m_tokens: (.cache_creation.ephemeral_5m_input_tokens // 0)
cache_read_input_tokens: (.cache_read_input_tokens // 0)
output_tokens: (.output_tokens // 0)
total_tokens: (.total_tokens // 0)
web_search_requests: (.server_tool_use.web_search_requests // 0)
requests: (.requests // 0)
- kind: claude-ai-user-cost
selector:
query: 'true'
startingAt: '2026-01-01T00:00:00Z'
port:
entity:
mappings:
identifier: >-
.actor.user_id + "-" + .__starting_at[:10] + "-" + (.product // "all")
+ "-" + (.model // "all")
title: (.actor.name // .actor.email // .actor.user_id) + " - " + .__starting_at[:10]
blueprint: '"claude_ai_user_cost"'
properties:
record_date: .__starting_at
range_end: .__ending_at
user_id: .actor.user_id
user_name: .actor.name
email: .actor.email
deleted: (.actor.deleted // false)
product: .product
model: .model
currency: (.currency // "USD")
amount: ((.amount // "0") | tonumber) / 100
list_amount: ((.list_amount // "0") | tonumber) / 100
requests: (.requests // 0)
Advanced selector configuration
The available selectors depend on the active deployment mode. query applies to all resource kinds in both modes and defaults to 'true'.
- Claude AI (Enterprise)
- Claude Platform
claude-ai-user-activity
This resource returns data for one specific day per call. The endpoint only returns data that is at least three days old, so the date window always ends roughly three days ago. To control the start of the window, provide one of timeFrame or startingDate (mutually exclusive). When you set neither, the integration defaults to a 30-day lookback.
| Field | Format | Description |
|---|---|---|
timeFrame | number | Number of days to look back, ending around three days ago. Must be greater than 0. Mutually exclusive with startingDate. Defaults to 30 when neither field is set. |
startingDate | YYYY-MM-DD | Iterates from this date once per day up to around three days ago, clamped to 2026-01-01 (the earliest available data). Use for historical backfills. Mutually exclusive with timeFrame. |
Using timeFrame (recommended for ongoing syncs):
selector:
query: 'true'
timeFrame: 30 # look back 30 days, one API call per day
Using startingDate (for a historical backfill):
selector:
query: 'true'
startingDate: '2026-01-01' # iterate from this date, one API call per day
claude-ai-user-usage and claude-ai-user-cost
These resources return per-user data across a date range and share the same selector fields.
| Field | Type | Description |
|---|---|---|
startingAt | string | RFC 3339 UTC start of the range (inclusive), e.g. 2026-01-01T00:00:00Z. Automatically clamped to the last 31 days and no earlier than 2026-01-01. Defaults to 2026-01-01T00:00:00Z. |
endingAt | string | RFC 3339 UTC end of the range (exclusive). Defaults to now. The range spans at most 31 days. |
excludeDeletedUsers | boolean | When true, rows for deleted users are omitted. Defaults to false. |
products | array | Filter to specific seat-based product surfaces. Allowed values: chat, claude_code, cowork, office_agent, claude_in_chrome, claude_design. |
models | array | Filter to specific model names. |
groupBy | array | Break each user's row out by the given dimensions. Allowed values: product, model, context_window, inference_geo, speed. |
contextWindows | array | Filter to specific context-window pricing tiers. Allowed values: 0-200k, 200k-1M. |
inferenceGeos | array | Filter to specific inference regions. Allowed values: global, us, not_available. |
speeds | array | Filter to fast or standard inference mode. Allowed values: fast, standard. |
selector:
query: 'true'
startingAt: '2026-01-01T00:00:00Z'
endingAt: '2026-01-31T00:00:00Z'
excludeDeletedUsers: false
products: [chat, claude_code]
groupBy: [product, model]
The Claude Platform selectors behave as follows:
startingDateis required forclaude-platform-usage-recordandclaude-platform-cost-record. Forclaude-platform-code-analytics, eitherstartingDateortimeFramemust be provided (mutually exclusive).bucketWidthcontrols time granularity for usage and cost resources.groupByis available forclaude-platform-usage-recordand lets you break down usage by dimensions.
claude-platform-usage-record
selector:
query: 'true'
startingDate: '2026-01-01T00:00:00Z'
bucketWidth: 1d # supported: 1m | 1h | 1d
groupBy: [workspace_id]
startingDatemust use ISO-8601 UTC format (YYYY-MM-DDTHH:MM:SSZ).bucketWidthsupports1m,1h, and1dfor usage records.groupBysupports dimensions such asapi_key_id,workspace_id,context_window,speed,inference_geo,account_id,service_account_id,model, andservice_tier.
claude-platform-cost-record
selector:
query: 'true'
startingDate: '2026-01-01T00:00:00Z'
bucketWidth: 1d
startingDatemust use ISO-8601 UTC format (YYYY-MM-DDTHH:MM:SSZ).bucketWidthsupports1donly for cost records in this integration.
claude-platform-code-analytics
The API returns data for one specific day per call. To control the date window, provide exactly one of the following fields:
| Field | Format | Description |
|---|---|---|
timeFrame | number | Number of days to look back from today. The integration calls the API once per day for each of the last N days. Recommended for ongoing syncs. |
startingDate | YYYY-MM-DD | Iterates from this date to today, calling the API once per day. Use for historical backfills. A warning is logged and no data is fetched if the date is in the future. |
timeFrame and startingDate cannot both be set on claude-platform-code-analytics. Providing neither or both will cause a validation error.
Using timeFrame (recommended for ongoing syncs):
selector:
query: 'true'
timeFrame: 30 # fetch the last 30 days, one API call per day
Using startingDate (for a historical backfill):
selector:
query: 'true'
startingDate: '2026-01-01' # iterate from this date to today
Mapping & examples per resource
To view and test the integration mapping against sample API responses, use the jq playground in your data sources page.
- Claude AI (Enterprise)
- Claude Platform
Monitoring and sync status
To learn more about how to monitor and check the sync status of your integration, see the relevant documentation.
Migration guide
If you currently ingest Claude metrics through a custom Ocean integration, migrate to the dedicated Claude AI integration:
- Create the new Claude AI data source from your data sources page.
- Copy your existing Claude API credentials into the new integration setup.
- Move your custom blueprint and mapping configuration into the dedicated integration.
- Run a sync and validate that records are ingested for all enabled resources.
- Disable the legacy custom Ocean Claude integration after validation.