references/metric-configuration.md·Markdown·114 KB·View on GitHub
All metrics use kind: "ExperimentMetric". Legacy kinds (ExperimentTrendsQuery, ExperimentFunnelsQuery) are rejected.
The full Pydantic schema below is rendered from posthog/schema.py at build
time — if a field is missing here, fix the model. It is the ExperimentMetric
discriminated union: pick the variant matching your metric_type (mean,
funnel, ratio, retention) under $defs, and read that variant’s
required array for the mandatory fields. The shared event-source building
blocks (EventsNode, ActionsNode, ExperimentDataWarehouseNode) and the
property-filter types are defined once under $defs and referenced by $ref.
The schema is authoritative; the prose and examples below are guidance.
Average of a numeric property per user. Use for revenue per user, session
duration, page views per user, and similar magnitudes. Drives the math via the
source.math / source.math_property pair on a single EventsNode,
ActionsNode, or ExperimentDataWarehouseNode.
Conversion rate from exposure through one or more ordered actions. The
experiment’s exposure event is automatically prepended as step_0, so even a
single entry in series creates a valid 2-step funnel (exposure → action).
Rate of one event relative to another. Each side (numerator, denominator)
is an EventsNode / ActionsNode / ExperimentDataWarehouseNode with its own
math and math_property — the math determines how each side is aggregated
before the ratio is taken.
Use for revenue per pageview, click-through rate, error rate, engagement
ratios.
To divide a property sum by an event count, the numerator’s math is "sum"
and math_property names the numeric property to sum. The denominator stays
at the default count.
A property filter scopes which events count — it does not sum them. The
numerator above counts purchases that have a revenue property, not the revenue
total. Aggregation lives in math / math_property, never in a filter.
Whether users return after initial exposure. Tracks start_event →
completion_event over a window defined by retention_window_start,
retention_window_end, and retention_window_unit. start_handling is
required and controls how users with multiple start events are anchored:
"first_seen" (anchor on first occurrence) or "last_seen" (anchor on most
recent).
The window is measured from the start event and bucketed by
retention_window_unit, which is "day" or "hour". The start occurrence never
counts as its own completion — only a distinct later event does — so the start
and completion events may be the same:
Different events (e.g. $pageview → uploaded_file) — conversion retention:
“did the user reach the target action within the window?”
Same event (e.g. nav_panel_clicked → nav_panel_clicked) —
repeat retention: “did the user fire it again within the window?” From 0
counts a repeat from the same period onward (same-day/same-hour repeats count);
From N (N ≥ 1) requires the repeat in a later period. Use start_handling: "first_seen"
so in-experiment repeats fall after the anchor — last_seen anchors on the user’s
final occurrence, which has no in-experiment activity after it.
Measures “of users who clicked the promoted product, how many clicked it again
within 7 days”. The first click anchors the window and never counts as its own
completion — only a later distinct click does, so a one-time clicker is correctly
counted as not retained.
A metric reaches an experiment via one of two independent experiment-update
fields. Attaching a shared metric does not touch the inline metrics array,
and vice versa.
Reuse a metric that already exists in the project instead of duplicating it
inline. Resolve the id with experiment-saved-metrics-list, then attach it:
Call experiment-saved-metrics-list to find the metric and its id (pass a
search term to resolve by name; results are paginated, so use limit/offset
when browsing a large project)
Call experiment-get to read the experiment’s current saved_metrics
Call experiment-update with saved_metrics_ids — this replaces all
existing saved-metric links, so send the full desired set:
The id here is the saved-metric id. Note the read/write asymmetry when you
rebuild the set from experiment-get: each entry in the returned saved_metrics
exposes a top-level id (the link row) and a separate saved_metric (the
metric id). Map each existing entry’s saved_metric into the id you
resend — sending the link id attaches the wrong metric or fails validation.
metadata is optional and defaults to primary. Pass an empty array to detach
all shared metrics.
To promote a one-off inline metric into a reusable shared metric, call
experiment-saved-metrics-create with the same query (the ExperimentMetric
object), then attach it via saved_metrics_ids as above.
"description": "Properties configurable in the interface",
"title": "Properties"
},
"response": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Response"
},
"version": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "version of the node, used for schema migrations",
"title": "Version"
}
},
"required": [
"id"
],
"title": "ActionsNode",
"type": "object"
},
"BaseMathType": {
"enum": [
"total",
"dau",
"weekly_active",
"monthly_active",
"unique_session",
"first_time_for_user",
"first_matching_event_for_user"
],
"title": "BaseMathType",
"type": "string"
},
"BehavioralEventSource": {
"enum": [
"events",
"actions"
],
"title": "BehavioralEventSource",
"type": "string"
},
"BehavioralPropertyFilter": {
"additionalProperties": false,
"properties": {
"event_filters": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/$defs/EventPropertyFilter"
},
{
"$ref": "#/$defs/PersonPropertyFilter"
},
{
"$ref": "#/$defs/ElementPropertyFilter"
},
{
"$ref": "#/$defs/FeaturePropertyFilter"
},
{
"$ref": "#/$defs/HogQLPropertyFilter"
}
]
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "Extra property filters the matching events must satisfy. Deliberately excludes nested behavioral/cohort filters and groups",
"title": "Event Filters"
},
"event_type": {
"$ref": "#/$defs/BehavioralEventSource"
},
"explicit_datetime": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Absolute or relative (e.g. -30d) lower date bound \u2014 alternative to time_value/time_interval",
"title": "Explicit Datetime"
},
"explicit_datetime_to": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Explicit Datetime To"
},
"key": {
"description": "Event name, or action id when event_type is 'actions'",
"title": "Key",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Label"
},
"negation": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"description": "Match persons who did NOT satisfy the criterion. Not the same as a low count \u2014 zero-occurrence persons never match count operators",
"title": "Negation"
},
"operator": {
"anyOf": [
{
"$ref": "#/$defs/PropertyOperator"
},
{
"type": "null"
}
],
"default": null,
"description": "Count comparison for performed_event_multiple, defaults to exact"
},
"operator_value": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "Count threshold for performed_event_multiple",
"title": "Operator Value"
},
"time_interval": {
"anyOf": [
{
"$ref": "#/$defs/TimeUnitType"
},
{
"type": "null"
}
],
"default": null
},
"time_value": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "Relative time window size, paired with time_interval",
"title": "Time Value"
},
"type": {
"const": "behavioral",
"default": "behavioral",
"description": "Person performed (or didn't perform) an event in a time window. ClickHouse-only \u2014 not evaluable by flags or CDP",
"title": "Type",
"type": "string"
},
"value": {
"$ref": "#/$defs/InlineBehavioralType"
}
},
"required": [
"event_type",
"key",
"value"
],
"title": "BehavioralPropertyFilter",
"type": "object"
},
"Breakdown": {
"additionalProperties": false,
"properties": {
"group_type_index": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Group Type Index"
},
"histogram_bin_count": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Histogram Bin Count"
},
"normalize_url": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Normalize Url"
},
"property": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
],
"title": "Property"
},
"type": {
"anyOf": [
{
"$ref": "#/$defs/MultipleBreakdownType"
},
{
"type": "null"
}
],
"default": null
}
},
"required": [
"property"
],
"title": "Breakdown",
"type": "object"
},
"BreakdownAttributionType": {
"enum": [
"first_touch",
"last_touch",
"all_events",
"step"
],
"title": "BreakdownAttributionType",
"type": "string"
},
"BreakdownFilter": {
"additionalProperties": false,
"properties": {
"breakdown": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array"
},
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Breakdown"
},
"breakdown_group_type_index": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Breakdown Group Type Index"
},
"breakdown_hide_other_aggregation": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Breakdown Hide Other Aggregation"
},
"breakdown_histogram_bin_count": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Breakdown Histogram Bin Count"
},
"breakdown_limit": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Breakdown Limit"
},
"breakdown_normalize_url": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Breakdown Normalize Url"
},
"breakdown_path_cleaning": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Breakdown Path Cleaning"
},
"breakdown_type": {
"anyOf": [
{
"$ref": "#/$defs/BreakdownType"
},
{
"type": "null"
}
],
"default": "event"
},
"breakdowns": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Breakdown"
},
"maxItems": 3,
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Breakdowns"
}
},
"title": "BreakdownFilter",
"type": "object"
},
"BreakdownType": {
"enum": [
"cohort",
"person",
"event",
"event_metadata",
"group",
"session",
"hogql",
"data_warehouse",
"data_warehouse_person_property",
"revenue_analytics"
],
"title": "BreakdownType",
"type": "string"
},
"CalendarHeatmapMathType": {
"enum": [
"total",
"dau"
],
"title": "CalendarHeatmapMathType",
"type": "string"
},
"CohortPropertyFilter": {
"additionalProperties": false,
"properties": {
"cohort_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Cohort Name"
},
"key": {
"const": "id",
"default": "id",
"title": "Key",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Label"
},
"operator": {
"anyOf": [
{
"$ref": "#/$defs/PropertyOperator"
},
{
"type": "null"
}
],
"default": "in"
},
"type": {
"const": "cohort",
"default": "cohort",
"title": "Type",
"type": "string"
},
"value": {
"title": "Value",
"type": "integer"
}
},
"required": [
"value"
],
"title": "CohortPropertyFilter",
"type": "object"
},
"CountPerActorMathType": {
"enum": [
"avg_count_per_actor",
"min_count_per_actor",
"max_count_per_actor",
"median_count_per_actor",
"p75_count_per_actor",
"p90_count_per_actor",
"p95_count_per_actor",
"p99_count_per_actor"
],
"title": "CountPerActorMathType",
"type": "string"
},
"CurrencyCode": {
"enum": [
"AED",
"AFN",
"ALL",
"AMD",
"ANG",
"AOA",
"ARS",
"AUD",
"AWG",
"AZN",
"BAM",
"BBD",
"BDT",
"BGN",
"BHD",
"BIF",
"BMD",
"BND",
"BOB",
"BRL",
"BSD",
"BTC",
"BTN",
"BWP",
"BYN",
"BZD",
"CAD",
"CDF",
"CHF",
"CLP",
"CNY",
"COP",
"CRC",
"CVE",
"CZK",
"DJF",
"DKK",
"DOP",
"DZD",
"EGP",
"ERN",
"ETB",
"EUR",
"FJD",
"GBP",
"GEL",
"GHS",
"GIP",
"GMD",
"GNF",
"GTQ",
"GYD",
"HKD",
"HNL",
"HRK",
"HTG",
"HUF",
"IDR",
"ILS",
"INR",
"IQD",
"IRR",
"ISK",
"JMD",
"JOD",
"JPY",
"KES",
"KGS",
"KHR",
"KMF",
"KRW",
"KWD",
"KYD",
"KZT",
"LAK",
"LBP",
"LKR",
"LRD",
"LTL",
"LVL",
"LSL",
"LYD",
"MAD",
"MDL",
"MGA",
"MKD",
"MMK",
"MNT",
"MOP",
"MRU",
"MTL",
"MUR",
"MVR",
"MWK",
"MXN",
"MYR",
"MZN",
"NAD",
"NGN",
"NIO",
"NOK",
"NPR",
"NZD",
"OMR",
"PAB",
"PEN",
"PGK",
"PHP",
"PKR",
"PLN",
"PYG",
"QAR",
"RON",
"RSD",
"RUB",
"RWF",
"SAR",
"SBD",
"SCR",
"SDG",
"SEK",
"SGD",
"SRD",
"SSP",
"STN",
"SYP",
"SZL",
"THB",
"TJS",
"TMT",
"TND",
"TOP",
"TRY",
"TTD",
"TWD",
"TZS",
"UAH",
"UGX",
"USD",
"UYU",
"UZS",
"VES",
"VND",
"VUV",
"WST",
"XAF",
"XCD",
"XOF",
"XPF",
"YER",
"ZAR",
"ZMW"
],
"title": "CurrencyCode",
"type": "string"
},
"DataWarehousePersonPropertyFilter": {
"additionalProperties": false,
"properties": {
"key": {
"title": "Key",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Label"
},
"operator": {
"$ref": "#/$defs/PropertyOperator"
},
"type": {
"const": "data_warehouse_person_property",
"default": "data_warehouse_person_property",
"title": "Type",
"type": "string"
},
"value": {
"anyOf": [
{
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
},
"type": "array"
},
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Value"
}
},
"required": [
"key",
"operator"
],
"title": "DataWarehousePersonPropertyFilter",
"type": "object"
},
"DataWarehousePropertyFilter": {
"additionalProperties": false,
"properties": {
"key": {
"title": "Key",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Label"
},
"operator": {
"$ref": "#/$defs/PropertyOperator"
},
"type": {
"const": "data_warehouse",
"default": "data_warehouse",
"title": "Type",
"type": "string"
},
"value": {
"anyOf": [
{
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
},
"type": "array"
},
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Value"
}
},
"required": [
"key",
"operator"
],
"title": "DataWarehousePropertyFilter",
"type": "object"
},
"DurationType": {
"enum": [
"duration",
"active_seconds",
"inactive_seconds"
],
"title": "DurationType",
"type": "string"
},
"ElementPropertyFilter": {
"additionalProperties": false,
"properties": {
"key": {
"$ref": "#/$defs/Key10"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Label"
},
"operator": {
"$ref": "#/$defs/PropertyOperator"
},
"type": {
"const": "element",
"default": "element",
"title": "Type",
"type": "string"
},
"value": {
"anyOf": [
{
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
},
"type": "array"
},
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Value"
}
},
"required": [
"key",
"operator"
],
"title": "ElementPropertyFilter",
"type": "object"
},
"EmptyPropertyFilter": {
"additionalProperties": false,
"properties": {
"type": {
"const": "empty",
"default": "empty",
"title": "Type",
"type": "string"
}
},
"title": "EmptyPropertyFilter",
"type": "object"
},
"ErrorTrackingIssueFilter": {
"additionalProperties": false,
"properties": {
"key": {
"title": "Key",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Label"
},
"operator": {
"$ref": "#/$defs/PropertyOperator"
},
"type": {
"const": "error_tracking_issue",
"default": "error_tracking_issue",
"title": "Type",
"type": "string"
},
"value": {
"anyOf": [
{
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
},
"type": "array"
},
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Value"
}
},
"required": [
"key",
"operator"
],
"title": "ErrorTrackingIssueFilter",
"type": "object"
},
"EventMetadataPropertyFilter": {
"additionalProperties": false,
"properties": {
"key": {
"title": "Key",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Label"
},
"operator": {
"$ref": "#/$defs/PropertyOperator"
},
"type": {
"const": "event_metadata",
"default": "event_metadata",
"title": "Type",
"type": "string"
},
"value": {
"anyOf": [
{
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
},
"type": "array"
},
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Value"
}
},
"required": [
"key",
"operator"
],
"title": "EventMetadataPropertyFilter",
"type": "object"
},
"EventPropertyFilter": {
"additionalProperties": false,
"properties": {
"key": {
"title": "Key",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Label"
},
"operator": {
"anyOf": [
{
"$ref": "#/$defs/PropertyOperator"
},
{
"type": "null"
}
],
"default": "exact"
},
"type": {
"const": "event",
"default": "event",
"description": "Event properties",
"title": "Type",
"type": "string"
},
"value": {
"anyOf": [
{
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
},
"type": "array"
},
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Value"
}
},
"required": [
"key"
],
"title": "EventPropertyFilter",
"type": "object"
},
"EventsNode": {
"additionalProperties": false,
"properties": {
"custom_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Custom Name"
},
"event": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The event or `null` for all events.",
"description": "When set, reports the percentage of users whose per-user summed/counted value reaches or exceeds this threshold. Only meaningful for sum/count math types.",
"title": "Threshold"
},
"upper_bound_percentile": {
"anyOf": [
{
"maximum": 1.0,
"minimum": 0.0,
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "Winsorization upper percentile bound, as a fraction in [0, 1] (e.g. 0.99 for the 99th percentile).",
"title": "Upper Bound Percentile"
},
"uuid": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Uuid"
},
"version": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "version of the node, used for schema migrations",
"title": "Version"
}
},
"required": [
"source"
],
"title": "ExperimentMeanMetric",
"type": "object"
},
"ExperimentMetricGoal": {
"enum": [
"increase",
"decrease"
],
"title": "ExperimentMetricGoal",
"type": "string"
},
"ExperimentMetricMathType": {
"enum": [
"total",
"sum",
"unique_session",
"min",
"max",
"avg",
"dau",
"unique_group",
"hogql"
],
"title": "ExperimentMetricMathType",
"type": "string"
},
"ExperimentMetricOutlierHandling": {
"additionalProperties": false,
"properties": {
"ignore_zeros": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Ignore Zeros"
},
"lower_bound_percentile": {
"anyOf": [
{
"maximum": 1.0,
"minimum": 0.0,
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "Winsorization lower percentile bound, as a fraction in [0, 1] (e.g. 0.01 for the 1st percentile).",
"title": "Lower Bound Percentile"
},
"upper_bound_percentile": {
"anyOf": [
{
"maximum": 1.0,
"minimum": 0.0,
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "Winsorization upper percentile bound, as a fraction in [0, 1] (e.g. 0.99 for the 99th percentile).",