> For the complete documentation index, see llms.txt.
Skip to main content

Check out Port for yourself ➜ 

Claude AI

Loading version...

Port's Claude AI integration allows you to ingest Claude usage, cost, and Claude Code analytics metrics into your software catalog.

Prerequisites

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:

Default mapping configuration (Click to expand)
resources:
- kind: claude-usage-record
selector:
query: .results | length > 0
startingDate: '2026-01-01T00:00:00Z'
bucketWidth: 1d
groupBy: []
port:
entity:
mappings:
identifier: .starting_at[:10] + "-usage"
title: '"Claude Usage - " + .starting_at[:10]'
blueprint: '"claude_usage_record"'
properties:
record_date: .starting_at
uncached_input_tokens: (.results[0].uncached_input_tokens // 0)
output_tokens: (.results[0].output_tokens // 0)
cache_read_input_tokens: (.results[0].cache_read_input_tokens // 0)
cache_creation_5m_tokens: (.results[0].cache_creation.ephemeral_5m_input_tokens // 0)
cache_creation_1h_tokens: (.results[0].cache_creation.ephemeral_1h_input_tokens // 0)
web_search_requests: (.results[0].server_tool_use.web_search_requests // 0)
- kind: claude-cost-record
selector:
query: .results | length > 0
startingDate: '2026-01-01T00:00:00Z'
bucketWidth: 1d
port:
entity:
mappings:
identifier: .starting_at[:10] + "-cost"
title: '"Claude Cost - " + .starting_at[:10]'
blueprint: '"claude_cost_record"'
properties:
record_date: .starting_at
amount: ((.results[0].amount // "0") | tonumber)
currency: (.results[0].currency // "USD")
- kind: claude-usage-record
selector:
query: .results | length > 0
startingDate: '2026-01-01T00:00:00Z'
bucketWidth: 1d
groupBy:
- workspace_id
port:
itemsToParse: .results
itemsToParseTopLevelTransform: false
entity:
mappings:
identifier: (.item.workspace_id // "default") + "-" + .starting_at[:10]
title: (.item.workspace_id // "default") + " - " + .starting_at[:10]
blueprint: '"claude_workspace_usage"'
properties:
record_date: .starting_at
workspace_id: (.item.workspace_id // "default")
uncached_input_tokens: (.item.uncached_input_tokens // 0)
output_tokens: (.item.output_tokens // 0)
cache_read_input_tokens: (.item.cache_read_input_tokens // 0)
cache_creation_5m_tokens: (.item.cache_creation.ephemeral_5m_input_tokens // 0)
cache_creation_1h_tokens: (.item.cache_creation.ephemeral_1h_input_tokens // 0)
web_search_requests: (.item.server_tool_use.web_search_requests // 0)
- kind: claude-usage-record
selector:
query: .results | length > 0
startingDate: '2026-01-01T00:00:00Z'
bucketWidth: 1d
groupBy:
- model
port:
itemsToParse: .results
itemsToParseTopLevelTransform: false
entity:
mappings:
identifier: .item.model + "-" + .starting_at[:10]
title: .item.model + " - " + .starting_at[:10]
blueprint: '"claude_model_usage"'
properties:
record_date: .starting_at
model: .item.model
uncached_input_tokens: (.item.uncached_input_tokens // 0)
output_tokens: (.item.output_tokens // 0)
cache_read_input_tokens: (.item.cache_read_input_tokens // 0)
cache_creation_5m_tokens: (.item.cache_creation.ephemeral_5m_input_tokens // 0)
cache_creation_1h_tokens: (.item.cache_creation.ephemeral_1h_input_tokens // 0)
web_search_requests: (.item.server_tool_use.web_search_requests // 0)
- kind: claude-code-analytics
selector:
query: 'true'
startingDate: '2026-01-01'
port:
entity:
mappings:
identifier: .organization_id + "-" + (.actor.api_key_name // .actor.email // "unknown") + "-" + .date[:10]
title: (.actor.api_key_name // .actor.email // "unknown") + " - " + .date[:10]
blueprint: '"claude_code_analytics"'
properties:
record_date: .date
organization_id: .organization_id
actor_type: .actor.type
actor_name: (.actor.api_key_name // .actor.email // "unknown")
terminal_type: .terminal_type
num_sessions: (.core_metrics.num_sessions // 0)
lines_added: (.core_metrics.lines_of_code.added // 0)
lines_removed: (.core_metrics.lines_of_code.removed // 0)
commits: (.core_metrics.commits_by_claude_code // 0)
pull_requests: (.core_metrics.pull_requests_by_claude_code // 0)
edit_tool_accepted: (.tool_actions.edit_tool.accepted // 0)
edit_tool_rejected: (.tool_actions.edit_tool.rejected // 0)
write_tool_accepted: (.tool_actions.write_tool.accepted // 0)
write_tool_rejected: (.tool_actions.write_tool.rejected // 0)
model_breakdown: .model_breakdown

Advanced selector configuration

  • query applies to all Claude resource kinds and defaults to 'true'.
  • startingDate is required for claude-usage-record and claude-cost-record. For claude-code-analytics, either startingDate or timeFrame must be provided (mutually exclusive).
  • bucketWidth controls time granularity for usage and cost resources.
  • groupBy is available for claude-usage-record and lets you break down usage by dimensions.

For claude-usage-record, you can use:

selector:
query: 'true'
startingDate: '2026-01-01T00:00:00Z'
bucketWidth: 1d # supported: 1m | 1h | 1d
groupBy: [workspace_id]
  • startingDate must use ISO-8601 UTC format (YYYY-MM-DDTHH:MM:SSZ).
  • bucketWidth supports 1m, 1h, and 1d for usage records.
  • groupBy supports dimensions such as api_key_id, workspace_id, context_window, speed, inference_geo, account_id, service_account_id, model, and service_tier.

For claude-cost-record, use:

selector:
query: 'true'
startingDate: '2026-01-01T00:00:00Z'
bucketWidth: 1d
  • startingDate must use ISO-8601 UTC format (YYYY-MM-DDTHH:MM:SSZ).
  • bucketWidth supports 1d only for cost records in this integration.

For claude-code-analytics, the API returns data for one specific day per call. To control the date window, provide exactly one of the following fields:

FieldFormatDescription
timeFramenumberNumber 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.
startingDateYYYY-MM-DDIterates 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.
Mutually exclusive

timeFrame and startingDate cannot both be set on claude-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.

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:

  1. Create the new Claude AI data source from your data sources page.
  2. Copy your existing Claude API credentials into the new integration setup.
  3. Move your custom blueprint and mapping configuration into the dedicated integration.
  4. Run a sync and validate that records are ingested for all enabled resources.
  5. Disable the legacy custom Ocean Claude integration after validation.

Visualize Claude metrics