Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ jobs:
lib/auth/sso/application/admit-sso-user.postgres.test.ts
lib/auth/sso/primary-provider.postgres.test.ts

- name: Verify cumulative billing timeout recovery in PostgreSQL
- name: Verify billing and organization activity in PostgreSQL
working-directory: apps/sim
env:
BILLING_USAGE_TEST_DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/sim_auth_scim
run: bunx vitest run lib/billing/core/usage-log.postgres.test.ts
run: bunx vitest run lib/billing/core/usage-log.postgres.test.ts lib/billing/core/organization-activity.postgres.test.ts

- name: Verify cumulative billing timeout recovery on PostgreSQL 16
if: matrix.provision == 'push'
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/docs/platform/enterprise/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Sim Enterprise adds organization controls for access, provisioning, operations,
| [Security](/platform/enterprise/security) | Manage session policies and view configured outbound IP addresses |
| [Session policies](/platform/enterprise/session-policies) | Set session lifetimes and revoke member sessions |
| [Audit logs](/platform/enterprise/audit-logs) | Investigate configuration and security events |
| [Usage tracking](/platform/enterprise/usage-tracking) | Review usage by member, workspace, model, and source |
| [Insights](/platform/enterprise/usage-tracking) | Explore credit usage, workflow performance, and recorded chat activity |
| [Data retention](/platform/enterprise/data-retention) | Set retention windows and configure PII redaction |
| [Data drains](/platform/enterprise/data-drains) | Export logs and Chat records to your own destination |
| [Custom blocks](/platform/enterprise/custom-blocks) | Share a workflow as a block across the organization |
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/docs/platform/enterprise/self-hosted.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Three features do not need a flag at all: **custom branding**, **session policie
| Directory provisioning (SCIM) | `SCIM_ENABLED` | `NEXT_PUBLIC_SCIM_ENABLED` |
| Custom branding — on by default | `WHITELABELING_ENABLED` | `NEXT_PUBLIC_WHITELABELING_ENABLED` |
| Audit logs | `AUDIT_LOGS_ENABLED` | `NEXT_PUBLIC_AUDIT_LOGS_ENABLED` |
| Usage tracking | `USAGE_MONITORING_ENABLED` | `NEXT_PUBLIC_USAGE_MONITORING_ENABLED` |
| Insights | `USAGE_MONITORING_ENABLED` | `NEXT_PUBLIC_USAGE_MONITORING_ENABLED` |
| Custom blocks | `CUSTOM_BLOCKS_ENABLED` | `NEXT_PUBLIC_CUSTOM_BLOCKS_ENABLED` |
| Session policies — on by default | `SESSION_POLICIES_ENABLED` | `NEXT_PUBLIC_SESSION_POLICIES_ENABLED` |
| Data retention deletion | `DATA_RETENTION_ENABLED` | `NEXT_PUBLIC_DATA_RETENTION_ENABLED` |
Expand Down
39 changes: 27 additions & 12 deletions apps/docs/content/docs/platform/enterprise/usage-tracking.mdx
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
---
title: Usage Tracking
description: See where your organization's credits go, by member, workspace, and model
title: Insights
description: Explore organization credit usage, workflow performance, and recorded chat activity
---

import { Callout } from 'fumadocs-ui/components/callout'
import { FAQ } from '@/components/ui/faq'
import { Image } from '@/components/ui/image'

Usage tracking shows how your organization consumes credits across every part of the platform — which members, which workspaces, which models, and which product features. Use it to monitor spend against your commitment, find what is driving it, and export the underlying events for chargeback.
Insights shows how your organization consumes credits across every part of the platform — which members, which workspaces, which models, and which product features. Use it to monitor spend against your commitment, find what is driving it, and export the underlying events for chargeback.

All figures are in **credits** (1 credit = $0.005). See [cost calculation](/platform/costs) for how credits are derived.
Spend figures are in **credits** (1 credit = $0.005). See [cost calculation](/platform/costs) for how credits are derived.

---

## Viewing usage

Go to **Settings → Organization → Usage tracking** in your workspace.

<Image src="/static/enterprise/usage-tracking-overview.png" alt="Usage tracking Overview tab showing the period selector, credits used against the organization limit, a daily usage chart, and a Sources section pairing a ranked list of sources with a radar chart of the same mix" width={900} height={781} className="mx-auto h-auto w-full max-w-xl" />
Go to **Settings → Organization → Insights** in your workspace.

The period selector applies to every tab:

Expand All @@ -36,7 +34,8 @@ The period selector applies to every tab:

| Tab | Answers |
|-----|---------|
| **Overview** | How much have we used, against what limit, and what kind of work was it |
| **Overview** | Credit consumption, recorded activity, workflow failure rate, and usage by source |
| **Activity** | Run trends and performance, grouped by workspace, workflow, chat member, or trigger |
| **Members** | Which people are driving usage |
| **Workspaces** | Which workspaces are driving usage — select one to drill in |
| **Models** | Which models we are paying for |
Expand All @@ -49,6 +48,22 @@ Selecting a workspace opens its detail view, which splits that workspace's usage

---

## Activity and performance

The **Activity** tab shows workflow runs, recorded chat runs, members with chat activity, and workflow failure rate. Group the breakdown by **Workspaces**, **Workflows**, **Members**, or **Triggers**, and sort by run volume, failure count, or average workflow duration. Member breakdowns rank chat runs only. Results are paginated; totals and sorting include the whole selected period, not just the visible page. Select a workspace to narrow the activity view, then use **All workspaces** to clear that filter.

- **Workflow runs** count retained execution records whose start time falls in the selected period, including runs that are still running, paused, or cancelled.
- **Recorded chat runs** count distinct recorded execution IDs across workspace and organization chats. Continuations count once, in the period containing their first retained start. Calls without a persisted chat run are not included.
- **Members with chat activity** count distinct users attributed to those chat runs. This measures recorded chat activity, not logins, all active users, or people billed for automated workflows.
- **Workflow failure rate** is failed runs divided by completed plus failed runs. Paused, cancelled, and unfinished runs do not enter the denominator. A dash means there are no completed or failed runs to measure.
- **Average duration** uses the recorded duration of completed or failed workflows. Missing durations are excluded; a dash means no duration is available.

Activity follows retained history and current organization/workspace ownership. Deleting history or moving a workspace can change historical activity totals. Status and duration reflect the latest recorded outcome, even for a run that started in an earlier period. The activity view does not read chat transcripts or workflow trace payloads.

Credit totals continue to come from the billing ledger. Activity counts need not match billing-event counts, and the credit export does not export activity. Exact per-chat cost, connector/skill adoption, and generated-artifact attribution are not available in this view.

---

## What each source means

A **source** is the part of the platform that consumed the credits. Every charge belongs to exactly one source, so the Sources breakdown always adds up to your total.
Expand Down Expand Up @@ -102,17 +117,17 @@ When a workspace or organization supplies its own provider key, Sim does not cha

## Exporting

**Export** downloads the events behind the current period and filters as a CSV with columns `Date, Source, Description, Workflow, Credits`. Credits are exported as plain numbers so the column can be summed, and carry decimals — an individual event often costs a fraction of a credit.
**Export credits** downloads the events behind the current period and filters as a CSV with columns `Date, Source, Description, Workflow, Credits`. Credits are exported as plain numbers so the column can be summed, and carry decimals — an individual event often costs a fraction of a credit.

**All events** opens the full ledger — every credit-consuming event, newest first, with its own filters and export.
**Credit events** opens the full ledger — every credit-consuming event, newest first, with its own filters and export.

Very large exports are capped. When that happens the download still succeeds and Sim tells you it was truncated; narrow the date range to capture everything.

---

<FAQ items={[
{
question: "Who can view usage tracking?",
question: "Who can view Insights?",
answer: "Organization owners and admins. On Sim Cloud you must be on the Enterprise plan. Regular members cannot see organization usage, including their own."
},
{
Expand Down Expand Up @@ -158,4 +173,4 @@ USAGE_MONITORING_ENABLED=true
NEXT_PUBLIC_USAGE_MONITORING_ENABLED=true
```

Once enabled, usage tracking is viewable in **Settings → Organization → Usage tracking** for organization owners and admins.
Once enabled, Insights is viewable in **Settings → Organization → Insights** for organization owners and admins.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { getOrganizationActivityBreakdownContract } from '@/lib/api/contracts/organization-activity'
import {
defineInternalJsonRoute,
internalRateLimits,
internalSessionAuth,
} from '@/lib/api/server/routes'
import { getOrganizationActivityBreakdown } from '@/lib/billing/application/organization-usage/get-organization-activity'
import { organizationUsageOperations } from '@/lib/billing/application/organization-usage/operations'
import { organizationUsageErrorPolicy } from '@/app/api/organizations/[id]/usage/error-policy'

export const dynamic = 'force-dynamic'

export const GET = defineInternalJsonRoute({
contract: getOrganizationActivityBreakdownContract,
auth: internalSessionAuth,
operation: organizationUsageOperations.readActivityBreakdown,
rateLimit: internalRateLimits.user({
bucketName: 'organization-activity',
}),
errorPolicy: organizationUsageErrorPolicy,
staticResponseHeaders: { 'Cache-Control': 'private, no-store' },
mapInput: ({ params, query }) => ({
...query,
organizationId: params.id,
startDate: query.startDate ? new Date(query.startDate) : undefined,
endDate: query.endDate ? new Date(query.endDate) : undefined,
}),
useCase: getOrganizationActivityBreakdown,
present: (result) => result,
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { getOrganizationActivitySummaryContract } from '@/lib/api/contracts/organization-activity'
import {
defineInternalJsonRoute,
internalRateLimits,
internalSessionAuth,
} from '@/lib/api/server/routes'
import { getOrganizationActivitySummary } from '@/lib/billing/application/organization-usage/get-organization-activity'
import { organizationUsageOperations } from '@/lib/billing/application/organization-usage/operations'
import { organizationUsageErrorPolicy } from '@/app/api/organizations/[id]/usage/error-policy'

export const dynamic = 'force-dynamic'

export const GET = defineInternalJsonRoute({
contract: getOrganizationActivitySummaryContract,
auth: internalSessionAuth,
operation: organizationUsageOperations.readActivitySummary,
rateLimit: internalRateLimits.user({
bucketName: 'organization-activity',
}),
errorPolicy: organizationUsageErrorPolicy,
staticResponseHeaders: { 'Cache-Control': 'private, no-store' },
mapInput: ({ params, query }) => ({
...query,
organizationId: params.id,
startDate: query.startDate ? new Date(query.startDate) : undefined,
endDate: query.endDate ? new Date(query.endDate) : undefined,
}),
useCase: getOrganizationActivitySummary,
present: (result) => result,
})
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const mocks = vi.hoisted(() => ({
vi.mock('@/hooks/queries/organization-search-stats', () => ({
useOrganizationSearchStats: mocks.query,
}))
vi.mock('@/components/charts', () => ({
vi.mock('@sim/emcn', async (importOriginal) => ({
...(await importOriginal<typeof import('@sim/emcn')>()),
BarChart: (props: unknown) => {
mocks.chart(props)
return <div>Daily chart</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
'use client'

import { type ReactNode, useMemo } from 'react'
import { Chip, ChipSelect, Tooltip } from '@sim/emcn'
import { BarChart, Chip, ChipSelect, Tooltip } from '@sim/emcn'
import { CircleInfo } from '@sim/emcn/icons'
import { useQueryStates } from 'nuqs'
import { BarChart } from '@/components/charts'
import {
SEARCH_STATS_PEOPLE_LIMIT,
SEARCH_STATS_SURFACE_LABELS,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
'use client'

import { memo, useCallback, useMemo, useRef, useState } from 'react'
import { Loader } from '@sim/emcn'
import { LineChart, Loader } from '@sim/emcn'
import { useParams } from 'next/navigation'
import { LineChart } from '@/components/charts'
import {
DashboardSegmentsContext,
type SegmentSelectionMode,
Expand Down
3 changes: 1 addition & 2 deletions apps/sim/app/workspace/[workspaceId]/logs/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from 'react'
import { Badge } from '@sim/emcn'
import { Badge, formatChartLatency } from '@sim/emcn'
import { formatRelativeTime } from '@sim/utils/formatting'
import { format } from 'date-fns'
import { formatChartLatency } from '@/components/charts/chart-format'
import { getIntegrationMetadata } from '@/lib/logs/get-trigger-options'
import { getBlock } from '@/blocks/registry'
import { CORE_TRIGGER_TYPES } from '@/stores/logs/filters/types'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('unified settings navigation', () => {
{ id: 'billing', label: 'Subscription', section: 'account' },
{ id: 'teammates', label: 'Teammates', section: 'workspace' },
{ id: 'organization', label: 'Members', section: 'organization' },
{ id: 'usage', label: 'Usage tracking', section: 'organization' },
{ id: 'usage', label: 'Insights', section: 'organization' },
{ id: 'secrets', label: 'Secrets', section: 'workspace' },
{ id: 'connected-accounts', label: 'Connected accounts', section: 'organization' },
{ id: 'custom-tools', label: 'Custom tools', section: 'workspace' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ describe('workspace SettingsSidebar organization rollout', () => {

expect(workspaceLink('organization')).toHaveTextContent('Members')
expect(workspaceLink('billing')).toHaveTextContent('Subscription')
expect(workspaceLink('usage')).toHaveTextContent('Usage tracking')
expect(workspaceLink('usage')).toHaveTextContent('Insights')
expect(workspaceLink('sso')).toHaveTextContent('Single sign-on')
expect(workspaceLink('connected-accounts')).toHaveTextContent('Connected accounts')
expect(container.querySelector('a[href^="/o/"]')).toBeNull()
Expand Down
13 changes: 0 additions & 13 deletions apps/sim/components/charts/index.ts

This file was deleted.

102 changes: 0 additions & 102 deletions apps/sim/components/charts/use-chart-theme.ts

This file was deleted.

4 changes: 2 additions & 2 deletions apps/sim/components/settings/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,11 +476,11 @@ export const SETTINGS_SECTION_REGISTRY: readonly SettingsSectionRegistryEntry[]
},
},
{
label: 'Usage tracking',
label: 'Insights',
icon: ChartColumn,
unified: {
id: 'usage',
description: 'Monitor credit usage across your organization.',
description: 'Explore usage and activity across your organization.',
group: 'organization',
order: 1,
/**
Expand Down
Loading
Loading