Headlessly

Business Metrics

Track MRR, churn, NRR, LTV, and every KPI across your business with real Stripe data.

Real numbers, not placeholders. Financial metrics derive from Stripe. Pipeline metrics derive from CRM. Product metrics derive from GitHub. Everything flows through the immutable event log.

import { Metric } from '@headlessly/analytics'

// Financial metrics -- real Stripe data
const mrr = await Metric.get('mrr')           // $12,500
const churn = await Metric.get('churn_rate')   // 2.1%
const nrr = await Metric.get('nrr')            // 108%
const ltv = await Metric.get('ltv')             // $5,950
const arpu = await Metric.get('arpu')           // $49

// Pipeline metrics -- real CRM data
const leads = await Metric.get('leads')         // 47
const qualified = await Metric.get('qualified') // 12
const pipeline = await Metric.get('pipeline_value') // $340,000

How Metrics Work

Metrics are not manually entered. They compute from the entities that already exist in your system:

MetricSourceDerivation
MRRStripe subscriptionsSum of active amounts, normalized monthly
ARRMRRMRR x 12
Churn RateStripe eventsCancellations / total subscriptions
NRRStripe eventsIncluding expansions and contractions
LTVStripe historyRevenue per customer / churn rate
ARPUMRR / subscribersAverage revenue per unit
PipelineCRM dealsSum of open deal values
LeadsCRM contactsCount of contacts with stage = Lead
DAU/MAUBrowser eventsUnique users per day/month

The Metric Entity

import { Noun } from 'digital-objects'

export const Metric = Noun('Metric', {
  name: 'string!#',
  type: 'Counter | Gauge | Histogram | Rate',
  value: 'number!',
  unit: 'string?',
  dimensions: 'json?',
  record: 'Recorded',
  reset:  'Reset',
})

Metric types map to how values behave over time:

  • Counter -- monotonically increasing (total revenue, total signups)
  • Gauge -- point-in-time snapshot (MRR, open tickets, DAU)
  • Histogram -- distribution (response times, deal sizes)
  • Rate -- ratio over time (churn rate, conversion rate)

Full Dashboard Snapshot

import { Metric } from '@headlessly/analytics'

const metrics = await Metric.dashboard()
// {
//   mrr: 12_500, arr: 150_000, churn: 2.1, nrr: 108,
//   ltv: 5_950, arpu: 49, leads: 47, qualified: 12,
//   pipeline_value: 340_000, dau: 230, mau: 1_200
// }

Or use the universal status method for a cross-domain snapshot:

import { $ } from '@headlessly/sdk'

const state = await $.status()
// state.revenue  = { mrr: 12_500, churn: 2.1, nrr: 108, ltv: 5_950 }
// state.pipeline = { leads: 47, qualified: 12, deals_open: 8 }
// state.product  = { tasks_open: 23, blocked: 2 }
// state.support  = { tickets_open: 5, p0: 1, avg_response: '2h' }

Record Custom Metrics

Financial metrics auto-derive. Custom metrics you record yourself:

import { Metric } from '@headlessly/analytics'

await Metric.create({
  name: 'nps_score',
  type: 'Gauge',
  value: 72,
  unit: 'score',
})

await Metric.record({ id: 'metric_vN3xRfLp', value: 74 })

Watch Metrics

React to metric changes in real time:

import { Metric } from '@headlessly/analytics'
import { Agent } from '@headlessly/platform'

// Alert when churn spikes above threshold
Metric.recorded((metric) => {
  if (metric.name === 'churn_rate' && metric.value > 3.0) {
    Agent.deploy('churn-alert', { churn: metric.value })
  }
})

// Cross-domain reaction via $ context
Metric.recorded((metric, $) => {
  if (metric.name === 'churn_rate' && metric.value > 5.0) {
    $.Campaign.create({ name: 'Win-back', type: 'Email', segment: 'churned_30d' })
  }
})

Metric History

Every Metric.record() appends to the immutable event log. Query historical values for trend analysis:

import { Metric } from '@headlessly/analytics'

const history = await Metric.find({
  name: 'mrr',
  dimensions: { period: 'monthly' },
})
// [{ value: 8_200, timestamp: '2025-09' }, { value: 10_100, timestamp: '2025-10' }, ...]

MCP Access

headless.ly/mcp#search
{ "type": "Metric", "filter": { "type": "Gauge" } }
headless.ly/mcp#fetch
{ "type": "Metric", "id": "mrr" }
headless.ly/mcp#do
const state = await $.status()
if (state.revenue.churn > 3) {
  await $.Campaign.create({ name: 'Win-back', type: 'Email' })
}

REST API

GET  /~my-startup/metrics                    # Full dashboard snapshot
GET  /~my-startup/Metric                     # All metric entities
GET  /~my-startup/Metric/metric_vN3xRfLp     # Single metric
POST /~my-startup/Metric/metric_vN3xRfLp/record  { "value": 74 }

CLI

npx @headlessly/cli Metric.dashboard
npx @headlessly/cli Metric.get mrr
npx @headlessly/cli Metric.record metric_vN3xRfLp --value 74
npx @headlessly/cli status

On this page