Experiments

For instructions on how to authenticate to use this endpoint, see API overview.

Endpoints

GET
POST
GET
PATCH
DELETE
GET
POST
POST
POST
POST
POST
GET
GET
POST
GET
GET
GET
POST
POST

List all experiments

List experiments for the current project. Supports filtering by status and archival state.

Required API key scopes

experiment:read

Query parameters

  • archived
    boolean
  • created_by_id
    string
  • event
    string
  • excluded_tags
    string
  • feature_flag_id
    integer
  • limit
    integer
  • offset
    integer
  • order
    string
  • prompt_name
    string
  • search
    string
  • status
    string
    One of: "all""complete""draft""exposure_frozen""paused""running""stopped"
  • tags
    string

Response


Example request

GET /api/projects/:project_id/experiments
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/

Example response

Status 200
RESPONSE
{
"count": 123,
"next": "http://api.example.org/accounts/?offset=400&limit=100",
"previous": "http://api.example.org/accounts/?offset=200&limit=100",
"results": [
{
"id": 0,
"name": "string",
"description": "string",
"start_date": "2019-08-24T14:15:22Z",
"end_date": "2019-08-24T14:15:22Z",
"feature_flag_key": "string",
"feature_flag": {
"id": 0,
"team_id": 0,
"name": "string",
"key": "string",
"filters": {},
"deleted": true,
"active": true,
"ensure_experience_continuity": true,
"version": -2147483648,
"evaluation_runtime": "server",
"bucketing_identifier": "distinct_id",
"evaluation_contexts": [
"string"
]
},
"holdout": {
"id": 0,
"name": "string",
"description": "string",
"filters": [
{
"properties": [
{
"key": "string",
"type": "cohort",
"cohort_name": "string",
"group_type_index": 0,
"value": null,
"operator": "exact"
}
],
"rollout_percentage": 0.1,
"variant": "string",
"aggregation_group_type_index": 0
}
],
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"user_access_level": "string"
},
"exposure_cohort": 0,
"parameters": {
"minimum_detectable_effect": null,
"variant_notes": null
},
"running_time_calculation": {
"exposure_estimate_config": null,
"minimum_detectable_effect": null,
"recommended_running_time": null,
"recommended_sample_size": null
},
"excluded_variants": [
"string"
],
"archived": false,
"deleted": true,
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"type": "web",
"conclusion": "won",
"conclusion_comment": "string",
"status": "draft",
"is_legacy": true,
"user_access_level": "string",
"tags": [
"string"
]
}
]
}

Create experiments

Also available via the PostHog MCP server:

  • experiment-create — Create experiment

Create a new experiment in draft status with optional metrics.

Required API key scopes

experiment:write

Request parameters

  • name
    string
  • description
    string | null
  • start_date
    string | null
  • end_date
    string | null
  • feature_flag_key
    string
  • feature_flag
  • holdout_id
    integer | null
  • parameters
  • running_time_calculation
  • excluded_variants
    array | null
  • secondary_metrics
  • saved_metrics_ids
    array | null
  • filters
  • archived
    boolean
    Default: false
  • deleted
    boolean | null
  • type
  • exposure_criteria
  • metrics
  • metrics_secondary
  • stats_config
  • scheduling_config
  • allow_unknown_events
    boolean
    Default: false
  • _create_in_folder
    string
  • conclusion
  • conclusion_comment
    string | null
  • repository
    string | null
  • primary_metrics_ordered_uuids
    array | null
  • secondary_metrics_ordered_uuids
    array | null
  • only_count_matured_users
    boolean
  • update_feature_flag_params
    boolean
    Default: false
  • version
    integer | null
  • original_experiment
    object | null
  • tags
    array

Response


Example request

POST /api/projects/:project_id/experiments
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/\
-d name="string",\
-d feature_flag_key="string"

Example response

Status 201
RESPONSE
{
"id": 0,
"name": "string",
"description": "string",
"start_date": "2019-08-24T14:15:22Z",
"end_date": "2019-08-24T14:15:22Z",
"feature_flag_key": "string",
"feature_flag": {
"id": 0,
"team_id": 0,
"name": "string",
"key": "string",
"filters": {},
"deleted": true,
"active": true,
"ensure_experience_continuity": true,
"version": -2147483648,
"evaluation_runtime": "server",
"bucketing_identifier": "distinct_id",
"evaluation_contexts": [
"string"
]
},
"holdout": {
"id": 0,
"name": "string",
"description": "string",
"filters": [
{
"properties": [
{
"key": "string",
"type": "cohort",
"cohort_name": "string",
"group_type_index": 0,
"value": null,
"operator": "exact"
}
],
"rollout_percentage": 0.1,
"variant": "string",
"aggregation_group_type_index": 0
}
],
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"user_access_level": "string"
},
"holdout_id": 0,
"exposure_cohort": 0,
"parameters": {
"minimum_detectable_effect": null,
"variant_notes": null
},
"running_time_calculation": {
"exposure_estimate_config": null,
"minimum_detectable_effect": null,
"recommended_running_time": null,
"recommended_sample_size": null
},
"excluded_variants": [
"string"
],
"secondary_metrics": null,
"saved_metrics": [
{
"id": 0,
"experiment": 0,
"saved_metric": 0,
"metadata": null,
"created_at": "2019-08-24T14:15:22Z",
"query": null,
"name": "string",
"effective_query": {
"breakdownFilter": null,
"conversion_window": null,
"conversion_window_unit": null,
"fingerprint": null,
"goal": null,
"ignore_zeros": null,
"isSharedMetric": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "mean",
"name": null,
"response": null,
"sharedMetricId": null,
"source": {
"custom_name": null,
"event": null,
"fixedProperties": null,
"kind": "EventsNode",
"limit": null,
"math": null,
"math_group_type_index": null,
"math_hogql": null,
"math_multiplier": null,
"math_property": null,
"math_property_revenue_currency": null,
"math_property_type": null,
"name": null,
"optionalInFunnel": null,
"orderBy": null,
"properties": null,
"response": null,
"version": null
},
"threshold": null,
"upper_bound_percentile": null,
"uuid": null,
"version": null
}
}
],
"saved_metrics_ids": [
null
],
"filters": null,
"archived": false,
"deleted": true,
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"type": "web",
"exposure_criteria": {
"activation_config": null,
"exposure_config": null,
"filterTestAccounts": null,
"multiple_variant_handling": null
},
"metrics": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"metrics_secondary": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"stats_config": null,
"scheduling_config": null,
"allow_unknown_events": false,
"_create_in_folder": "string",
"conclusion": "won",
"conclusion_comment": "string",
"flag_cleanup_task_id": "72bdc9e1-c8bb-44f1-8473-a75871329c84",
"repository": "string",
"primary_metrics_ordered_uuids": [
"string"
],
"secondary_metrics_ordered_uuids": [
"string"
],
"only_count_matured_users": true,
"update_feature_flag_params": false,
"version": 0,
"original_experiment": {},
"status": "draft",
"is_legacy": true,
"can_freeze_exposure": true,
"resolved_exposure_event": "string",
"health": {
"findings": [
{
"code": "flag_off_while_running",
"subcode": "string",
"reason": "string",
"severity": "critical",
"title": "string",
"detail": "string",
"evidence": {
"property1": "string",
"property2": "string"
},
"actions": [
"open_feature_flag"
],
"diagnostic_ref": "string",
"check": "flag_state"
}
],
"checks": [
{
"key": "flag_state",
"name": "string",
"description": "string",
"status": "passed",
"reason": "string",
"values": {
"property1": "string",
"property2": "string"
},
"rule": {
"value": "exposed_count",
"threshold": 0.1,
"warns": "above",
"test": "chi_squared",
"minimum": {
"value": "exposed_count",
"threshold": 0.1
}
}
}
],
"setup": {
"release_conditions": [
{
"rollout_percentage": 0.1,
"property_count": 0,
"aggregation_group_type_index": 0
}
],
"early_exit": true,
"bucketing_identifier": "distinct_id",
"aggregation_group_type_index": 0,
"evaluation_runtime": "server",
"evaluation_contexts": [
"string"
],
"ensure_experience_continuity": true
}
},
"user_access_level": "string",
"tags": [
"string"
]
}

Retrieve experiments

Also available via the PostHog MCP server:

  • experiment-get — Get experiment details

Retrieve a single experiment by ID, including its current status, metrics, feature flag, and results metadata.

Required API key scopes

experiment:read

Path parameters

  • id
    integer

Response


Example request

GET /api/projects/:project_id/experiments/:id
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/

Example response

Status 200
RESPONSE
{
"id": 0,
"name": "string",
"description": "string",
"start_date": "2019-08-24T14:15:22Z",
"end_date": "2019-08-24T14:15:22Z",
"feature_flag_key": "string",
"feature_flag": {
"id": 0,
"team_id": 0,
"name": "string",
"key": "string",
"filters": {},
"deleted": true,
"active": true,
"ensure_experience_continuity": true,
"version": -2147483648,
"evaluation_runtime": "server",
"bucketing_identifier": "distinct_id",
"evaluation_contexts": [
"string"
]
},
"holdout": {
"id": 0,
"name": "string",
"description": "string",
"filters": [
{
"properties": [
{
"key": "string",
"type": "cohort",
"cohort_name": "string",
"group_type_index": 0,
"value": null,
"operator": "exact"
}
],
"rollout_percentage": 0.1,
"variant": "string",
"aggregation_group_type_index": 0
}
],
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"user_access_level": "string"
},
"holdout_id": 0,
"exposure_cohort": 0,
"parameters": {
"minimum_detectable_effect": null,
"variant_notes": null
},
"running_time_calculation": {
"exposure_estimate_config": null,
"minimum_detectable_effect": null,
"recommended_running_time": null,
"recommended_sample_size": null
},
"excluded_variants": [
"string"
],
"secondary_metrics": null,
"saved_metrics": [
{
"id": 0,
"experiment": 0,
"saved_metric": 0,
"metadata": null,
"created_at": "2019-08-24T14:15:22Z",
"query": null,
"name": "string",
"effective_query": {
"breakdownFilter": null,
"conversion_window": null,
"conversion_window_unit": null,
"fingerprint": null,
"goal": null,
"ignore_zeros": null,
"isSharedMetric": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "mean",
"name": null,
"response": null,
"sharedMetricId": null,
"source": {
"custom_name": null,
"event": null,
"fixedProperties": null,
"kind": "EventsNode",
"limit": null,
"math": null,
"math_group_type_index": null,
"math_hogql": null,
"math_multiplier": null,
"math_property": null,
"math_property_revenue_currency": null,
"math_property_type": null,
"name": null,
"optionalInFunnel": null,
"orderBy": null,
"properties": null,
"response": null,
"version": null
},
"threshold": null,
"upper_bound_percentile": null,
"uuid": null,
"version": null
}
}
],
"saved_metrics_ids": [
null
],
"filters": null,
"archived": false,
"deleted": true,
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"type": "web",
"exposure_criteria": {
"activation_config": null,
"exposure_config": null,
"filterTestAccounts": null,
"multiple_variant_handling": null
},
"metrics": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"metrics_secondary": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"stats_config": null,
"scheduling_config": null,
"allow_unknown_events": false,
"_create_in_folder": "string",
"conclusion": "won",
"conclusion_comment": "string",
"flag_cleanup_task_id": "72bdc9e1-c8bb-44f1-8473-a75871329c84",
"repository": "string",
"primary_metrics_ordered_uuids": [
"string"
],
"secondary_metrics_ordered_uuids": [
"string"
],
"only_count_matured_users": true,
"update_feature_flag_params": false,
"version": 0,
"original_experiment": {},
"status": "draft",
"is_legacy": true,
"can_freeze_exposure": true,
"resolved_exposure_event": "string",
"health": {
"findings": [
{
"code": "flag_off_while_running",
"subcode": "string",
"reason": "string",
"severity": "critical",
"title": "string",
"detail": "string",
"evidence": {
"property1": "string",
"property2": "string"
},
"actions": [
"open_feature_flag"
],
"diagnostic_ref": "string",
"check": "flag_state"
}
],
"checks": [
{
"key": "flag_state",
"name": "string",
"description": "string",
"status": "passed",
"reason": "string",
"values": {
"property1": "string",
"property2": "string"
},
"rule": {
"value": "exposed_count",
"threshold": 0.1,
"warns": "above",
"test": "chi_squared",
"minimum": {
"value": "exposed_count",
"threshold": 0.1
}
}
}
],
"setup": {
"release_conditions": [
{
"rollout_percentage": 0.1,
"property_count": 0,
"aggregation_group_type_index": 0
}
],
"early_exit": true,
"bucketing_identifier": "distinct_id",
"aggregation_group_type_index": 0,
"evaluation_runtime": "server",
"evaluation_contexts": [
"string"
],
"ensure_experience_continuity": true
}
},
"user_access_level": "string",
"tags": [
"string"
]
}

Update experiments

Also available via the PostHog MCP server:

  • experiment-update — Update experiment

Update an experiment. Use this to modify experiment properties such as name, description, metrics, variants, and configuration. Metrics can be added, changed and removed at any time. Feature-flag config (variants, rollout, payloads) is sent via the feature_flag object.

Required API key scopes

experiment:write

Path parameters

  • id
    integer

Request parameters

  • name
    string
  • description
    string | null
  • start_date
    string | null
  • end_date
    string | null
  • feature_flag_key
    string
  • feature_flag
  • holdout_id
    integer | null
  • parameters
  • running_time_calculation
  • excluded_variants
    array | null
  • secondary_metrics
  • saved_metrics_ids
    array | null
  • filters
  • archived
    boolean
    Default: false
  • deleted
    boolean | null
  • type
  • exposure_criteria
  • metrics
  • metrics_secondary
  • stats_config
  • scheduling_config
  • allow_unknown_events
    boolean
    Default: false
  • _create_in_folder
    string
  • conclusion
  • conclusion_comment
    string | null
  • repository
    string | null
  • primary_metrics_ordered_uuids
    array | null
  • secondary_metrics_ordered_uuids
    array | null
  • only_count_matured_users
    boolean
  • update_feature_flag_params
    boolean
    Default: false
  • version
    integer | null
  • original_experiment
    object | null
  • tags
    array

Response


Example request

PATCH /api/projects/:project_id/experiments/:id
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl -X PATCH \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/\
-d name="string"

Example response

Status 200
RESPONSE
{
"id": 0,
"name": "string",
"description": "string",
"start_date": "2019-08-24T14:15:22Z",
"end_date": "2019-08-24T14:15:22Z",
"feature_flag_key": "string",
"feature_flag": {
"id": 0,
"team_id": 0,
"name": "string",
"key": "string",
"filters": {},
"deleted": true,
"active": true,
"ensure_experience_continuity": true,
"version": -2147483648,
"evaluation_runtime": "server",
"bucketing_identifier": "distinct_id",
"evaluation_contexts": [
"string"
]
},
"holdout": {
"id": 0,
"name": "string",
"description": "string",
"filters": [
{
"properties": [
{
"key": "string",
"type": "cohort",
"cohort_name": "string",
"group_type_index": 0,
"value": null,
"operator": "exact"
}
],
"rollout_percentage": 0.1,
"variant": "string",
"aggregation_group_type_index": 0
}
],
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"user_access_level": "string"
},
"holdout_id": 0,
"exposure_cohort": 0,
"parameters": {
"minimum_detectable_effect": null,
"variant_notes": null
},
"running_time_calculation": {
"exposure_estimate_config": null,
"minimum_detectable_effect": null,
"recommended_running_time": null,
"recommended_sample_size": null
},
"excluded_variants": [
"string"
],
"secondary_metrics": null,
"saved_metrics": [
{
"id": 0,
"experiment": 0,
"saved_metric": 0,
"metadata": null,
"created_at": "2019-08-24T14:15:22Z",
"query": null,
"name": "string",
"effective_query": {
"breakdownFilter": null,
"conversion_window": null,
"conversion_window_unit": null,
"fingerprint": null,
"goal": null,
"ignore_zeros": null,
"isSharedMetric": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "mean",
"name": null,
"response": null,
"sharedMetricId": null,
"source": {
"custom_name": null,
"event": null,
"fixedProperties": null,
"kind": "EventsNode",
"limit": null,
"math": null,
"math_group_type_index": null,
"math_hogql": null,
"math_multiplier": null,
"math_property": null,
"math_property_revenue_currency": null,
"math_property_type": null,
"name": null,
"optionalInFunnel": null,
"orderBy": null,
"properties": null,
"response": null,
"version": null
},
"threshold": null,
"upper_bound_percentile": null,
"uuid": null,
"version": null
}
}
],
"saved_metrics_ids": [
null
],
"filters": null,
"archived": false,
"deleted": true,
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"type": "web",
"exposure_criteria": {
"activation_config": null,
"exposure_config": null,
"filterTestAccounts": null,
"multiple_variant_handling": null
},
"metrics": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"metrics_secondary": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"stats_config": null,
"scheduling_config": null,
"allow_unknown_events": false,
"_create_in_folder": "string",
"conclusion": "won",
"conclusion_comment": "string",
"flag_cleanup_task_id": "72bdc9e1-c8bb-44f1-8473-a75871329c84",
"repository": "string",
"primary_metrics_ordered_uuids": [
"string"
],
"secondary_metrics_ordered_uuids": [
"string"
],
"only_count_matured_users": true,
"update_feature_flag_params": false,
"version": 0,
"original_experiment": {},
"status": "draft",
"is_legacy": true,
"can_freeze_exposure": true,
"resolved_exposure_event": "string",
"health": {
"findings": [
{
"code": "flag_off_while_running",
"subcode": "string",
"reason": "string",
"severity": "critical",
"title": "string",
"detail": "string",
"evidence": {
"property1": "string",
"property2": "string"
},
"actions": [
"open_feature_flag"
],
"diagnostic_ref": "string",
"check": "flag_state"
}
],
"checks": [
{
"key": "flag_state",
"name": "string",
"description": "string",
"status": "passed",
"reason": "string",
"values": {
"property1": "string",
"property2": "string"
},
"rule": {
"value": "exposed_count",
"threshold": 0.1,
"warns": "above",
"test": "chi_squared",
"minimum": {
"value": "exposed_count",
"threshold": 0.1
}
}
}
],
"setup": {
"release_conditions": [
{
"rollout_percentage": 0.1,
"property_count": 0,
"aggregation_group_type_index": 0
}
],
"early_exit": true,
"bucketing_identifier": "distinct_id",
"aggregation_group_type_index": 0,
"evaluation_runtime": "server",
"evaluation_contexts": [
"string"
],
"ensure_experience_continuity": true
}
},
"user_access_level": "string",
"tags": [
"string"
]
}

Delete experiments

Hard delete of this model is not allowed. Use a patch API call to set "deleted" to true

Required API key scopes

experiment:write

Path parameters

  • id
    integer

Example request

DELETE /api/projects/:project_id/experiments/:id
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl -X DELETE \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/

Example response

Status 405 No response body

Retrieve experiments activity

Change history for this experiment.

Returns a paginated audit trail of changes to the experiment, its holdouts and shared metrics, and its linked feature flag: who made each change, what changed (field-level before/after values), and when. Ordered newest first.

Required API key scopes

activity_log:read

Path parameters

  • id
    integer

Query parameters

  • limit
    integer
    Default: 10
  • page
    integer
    Default: 1

Response


Example request

GET /api/projects/:project_id/experiments/:id/activity
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/activity/

Example response

Status 200
RESPONSE
{
"results": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"user": {},
"activity": "string",
"scope": "string",
"item_id": "string",
"detail": {
"id": "string",
"changes": [
{
"type": "string",
"action": "string",
"field": "string",
"before": null,
"after": null
}
],
"merge": {
"type": "string",
"source": null,
"target": null
},
"trigger": {
"job_type": "string",
"job_id": "string",
"payload": null
},
"name": "string",
"short_id": "string",
"type": "string"
},
"created_at": "2019-08-24T14:15:22Z",
"is_system": true,
"was_impersonated": true,
"client": "string"
}
],
"next": "http://example.com",
"previous": "http://example.com",
"total_count": 0
}
Status 404 No response body

Create experiments archive

Archive an ended experiment.

Hides the experiment from the default list view. The experiment can be restored at any time by updating archived=false. When the linked feature flag is still enabled, pass disable_feature_flag=true to also disable and archive it. Returns 400 if the experiment is already archived or has not ended yet.

Required API key scopes

experiment:write

Path parameters

  • id
    integer

Request parameters

  • disable_feature_flag
    boolean
    Default: false

Response


Example request

POST /api/projects/:project_id/experiments/:id/archive
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/archive/\
-d disable_feature_flag="boolean"

Example response

Status 200
RESPONSE
{
"id": 0,
"name": "string",
"description": "string",
"start_date": "2019-08-24T14:15:22Z",
"end_date": "2019-08-24T14:15:22Z",
"feature_flag_key": "string",
"feature_flag": {
"id": 0,
"team_id": 0,
"name": "string",
"key": "string",
"filters": {},
"deleted": true,
"active": true,
"ensure_experience_continuity": true,
"version": -2147483648,
"evaluation_runtime": "server",
"bucketing_identifier": "distinct_id",
"evaluation_contexts": [
"string"
]
},
"holdout": {
"id": 0,
"name": "string",
"description": "string",
"filters": [
{
"properties": [
{
"key": "string",
"type": "cohort",
"cohort_name": "string",
"group_type_index": 0,
"value": null,
"operator": "exact"
}
],
"rollout_percentage": 0.1,
"variant": "string",
"aggregation_group_type_index": 0
}
],
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"user_access_level": "string"
},
"holdout_id": 0,
"exposure_cohort": 0,
"parameters": {
"minimum_detectable_effect": null,
"variant_notes": null
},
"running_time_calculation": {
"exposure_estimate_config": null,
"minimum_detectable_effect": null,
"recommended_running_time": null,
"recommended_sample_size": null
},
"excluded_variants": [
"string"
],
"secondary_metrics": null,
"saved_metrics": [
{
"id": 0,
"experiment": 0,
"saved_metric": 0,
"metadata": null,
"created_at": "2019-08-24T14:15:22Z",
"query": null,
"name": "string",
"effective_query": {
"breakdownFilter": null,
"conversion_window": null,
"conversion_window_unit": null,
"fingerprint": null,
"goal": null,
"ignore_zeros": null,
"isSharedMetric": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "mean",
"name": null,
"response": null,
"sharedMetricId": null,
"source": {
"custom_name": null,
"event": null,
"fixedProperties": null,
"kind": "EventsNode",
"limit": null,
"math": null,
"math_group_type_index": null,
"math_hogql": null,
"math_multiplier": null,
"math_property": null,
"math_property_revenue_currency": null,
"math_property_type": null,
"name": null,
"optionalInFunnel": null,
"orderBy": null,
"properties": null,
"response": null,
"version": null
},
"threshold": null,
"upper_bound_percentile": null,
"uuid": null,
"version": null
}
}
],
"saved_metrics_ids": [
null
],
"filters": null,
"archived": false,
"deleted": true,
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"type": "web",
"exposure_criteria": {
"activation_config": null,
"exposure_config": null,
"filterTestAccounts": null,
"multiple_variant_handling": null
},
"metrics": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"metrics_secondary": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"stats_config": null,
"scheduling_config": null,
"allow_unknown_events": false,
"_create_in_folder": "string",
"conclusion": "won",
"conclusion_comment": "string",
"flag_cleanup_task_id": "72bdc9e1-c8bb-44f1-8473-a75871329c84",
"repository": "string",
"primary_metrics_ordered_uuids": [
"string"
],
"secondary_metrics_ordered_uuids": [
"string"
],
"only_count_matured_users": true,
"update_feature_flag_params": false,
"version": 0,
"original_experiment": {},
"status": "draft",
"is_legacy": true,
"can_freeze_exposure": true,
"resolved_exposure_event": "string",
"health": {
"findings": [
{
"code": "flag_off_while_running",
"subcode": "string",
"reason": "string",
"severity": "critical",
"title": "string",
"detail": "string",
"evidence": {
"property1": "string",
"property2": "string"
},
"actions": [
"open_feature_flag"
],
"diagnostic_ref": "string",
"check": "flag_state"
}
],
"checks": [
{
"key": "flag_state",
"name": "string",
"description": "string",
"status": "passed",
"reason": "string",
"values": {
"property1": "string",
"property2": "string"
},
"rule": {
"value": "exposed_count",
"threshold": 0.1,
"warns": "above",
"test": "chi_squared",
"minimum": {
"value": "exposed_count",
"threshold": 0.1
}
}
}
],
"setup": {
"release_conditions": [
{
"rollout_percentage": 0.1,
"property_count": 0,
"aggregation_group_type_index": 0
}
],
"early_exit": true,
"bucketing_identifier": "distinct_id",
"aggregation_group_type_index": 0,
"evaluation_runtime": "server",
"evaluation_contexts": [
"string"
],
"ensure_experience_continuity": true
}
},
"user_access_level": "string",
"tags": [
"string"
]
}

Create experiments copy to project

Copy an experiment into another project in the same organization as a new draft.

Required API key scopes

experiment:write

Path parameters

  • id
    integer

Request parameters

  • target_team_id
    integer
  • feature_flag_key
    string
  • name
    string

Response


Example request

POST /api/projects/:project_id/experiments/:id/copy_to_project
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/copy_to_project/\
-d target_team_id="integer"

Example response

Status 200
RESPONSE
{
"id": 0,
"name": "string",
"description": "string",
"start_date": "2019-08-24T14:15:22Z",
"end_date": "2019-08-24T14:15:22Z",
"feature_flag_key": "string",
"feature_flag": {
"id": 0,
"team_id": 0,
"name": "string",
"key": "string",
"filters": {},
"deleted": true,
"active": true,
"ensure_experience_continuity": true,
"version": -2147483648,
"evaluation_runtime": "server",
"bucketing_identifier": "distinct_id",
"evaluation_contexts": [
"string"
]
},
"holdout": {
"id": 0,
"name": "string",
"description": "string",
"filters": [
{
"properties": [
{
"key": "string",
"type": "cohort",
"cohort_name": "string",
"group_type_index": 0,
"value": null,
"operator": "exact"
}
],
"rollout_percentage": 0.1,
"variant": "string",
"aggregation_group_type_index": 0
}
],
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"user_access_level": "string"
},
"holdout_id": 0,
"exposure_cohort": 0,
"parameters": {
"minimum_detectable_effect": null,
"variant_notes": null
},
"running_time_calculation": {
"exposure_estimate_config": null,
"minimum_detectable_effect": null,
"recommended_running_time": null,
"recommended_sample_size": null
},
"excluded_variants": [
"string"
],
"secondary_metrics": null,
"saved_metrics": [
{
"id": 0,
"experiment": 0,
"saved_metric": 0,
"metadata": null,
"created_at": "2019-08-24T14:15:22Z",
"query": null,
"name": "string",
"effective_query": {
"breakdownFilter": null,
"conversion_window": null,
"conversion_window_unit": null,
"fingerprint": null,
"goal": null,
"ignore_zeros": null,
"isSharedMetric": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "mean",
"name": null,
"response": null,
"sharedMetricId": null,
"source": {
"custom_name": null,
"event": null,
"fixedProperties": null,
"kind": "EventsNode",
"limit": null,
"math": null,
"math_group_type_index": null,
"math_hogql": null,
"math_multiplier": null,
"math_property": null,
"math_property_revenue_currency": null,
"math_property_type": null,
"name": null,
"optionalInFunnel": null,
"orderBy": null,
"properties": null,
"response": null,
"version": null
},
"threshold": null,
"upper_bound_percentile": null,
"uuid": null,
"version": null
}
}
],
"saved_metrics_ids": [
null
],
"filters": null,
"archived": false,
"deleted": true,
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"type": "web",
"exposure_criteria": {
"activation_config": null,
"exposure_config": null,
"filterTestAccounts": null,
"multiple_variant_handling": null
},
"metrics": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"metrics_secondary": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"stats_config": null,
"scheduling_config": null,
"allow_unknown_events": false,
"_create_in_folder": "string",
"conclusion": "won",
"conclusion_comment": "string",
"flag_cleanup_task_id": "72bdc9e1-c8bb-44f1-8473-a75871329c84",
"repository": "string",
"primary_metrics_ordered_uuids": [
"string"
],
"secondary_metrics_ordered_uuids": [
"string"
],
"only_count_matured_users": true,
"update_feature_flag_params": false,
"version": 0,
"original_experiment": {},
"status": "draft",
"is_legacy": true,
"can_freeze_exposure": true,
"resolved_exposure_event": "string",
"health": {
"findings": [
{
"code": "flag_off_while_running",
"subcode": "string",
"reason": "string",
"severity": "critical",
"title": "string",
"detail": "string",
"evidence": {
"property1": "string",
"property2": "string"
},
"actions": [
"open_feature_flag"
],
"diagnostic_ref": "string",
"check": "flag_state"
}
],
"checks": [
{
"key": "flag_state",
"name": "string",
"description": "string",
"status": "passed",
"reason": "string",
"values": {
"property1": "string",
"property2": "string"
},
"rule": {
"value": "exposed_count",
"threshold": 0.1,
"warns": "above",
"test": "chi_squared",
"minimum": {
"value": "exposed_count",
"threshold": 0.1
}
}
}
],
"setup": {
"release_conditions": [
{
"rollout_percentage": 0.1,
"property_count": 0,
"aggregation_group_type_index": 0
}
],
"early_exit": true,
"bucketing_identifier": "distinct_id",
"aggregation_group_type_index": 0,
"evaluation_runtime": "server",
"evaluation_contexts": [
"string"
],
"ensure_experience_continuity": true
}
},
"user_access_level": "string",
"tags": [
"string"
]
}

Create experiments create exposure cohort for experiment

Mixin for ViewSets to handle approval-gate exceptions raised from decorated serializers.

Intercepts ApprovalRequired (409) and PolicyConflict (400) raised by the @approval_gate decorator on serializer methods and converts them into the same responses the viewset path produces (see decorators._result_to_response), so both paths share one contract.

Required API key scopes

experiment:write

Path parameters

  • id
    integer

Request parameters

  • name
    string
  • description
    string | null
  • start_date
    string | null
  • end_date
    string | null
  • feature_flag_key
    string
  • holdout_id
    integer | null
  • parameters
  • running_time_calculation
  • excluded_variants
    array | null
  • secondary_metrics
  • saved_metrics_ids
    array | null
  • filters
  • archived
    boolean
    Default: false
  • deleted
    boolean | null
  • type
  • exposure_criteria
  • metrics
  • metrics_secondary
  • stats_config
  • scheduling_config
  • allow_unknown_events
    boolean
    Default: false
  • _create_in_folder
    string
  • conclusion
  • conclusion_comment
    string | null
  • repository
    string | null
  • primary_metrics_ordered_uuids
    array | null
  • secondary_metrics_ordered_uuids
    array | null
  • only_count_matured_users
    boolean
  • update_feature_flag_params
    boolean
    Default: false
  • version
    integer | null
  • original_experiment
    object | null
  • tags
    array

Example request

POST /api/projects/:project_id/experiments/:id/create_exposure_cohort_for_experiment
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/create_exposure_cohort_for_experiment/\
-d name="string",\
-d feature_flag_key="string"

Example response

Status 200 No response body

Create experiments duplicate

Mixin for ViewSets to handle approval-gate exceptions raised from decorated serializers.

Intercepts ApprovalRequired (409) and PolicyConflict (400) raised by the @approval_gate decorator on serializer methods and converts them into the same responses the viewset path produces (see decorators._result_to_response), so both paths share one contract.

Required API key scopes

experiment:write

Path parameters

  • id
    integer

Request parameters

  • name
    string
  • description
    string | null
  • start_date
    string | null
  • end_date
    string | null
  • feature_flag_key
    string
  • holdout_id
    integer | null
  • parameters
  • running_time_calculation
  • excluded_variants
    array | null
  • secondary_metrics
  • saved_metrics_ids
    array | null
  • filters
  • archived
    boolean
    Default: false
  • deleted
    boolean | null
  • type
  • exposure_criteria
  • metrics
  • metrics_secondary
  • stats_config
  • scheduling_config
  • allow_unknown_events
    boolean
    Default: false
  • _create_in_folder
    string
  • conclusion
  • conclusion_comment
    string | null
  • repository
    string | null
  • primary_metrics_ordered_uuids
    array | null
  • secondary_metrics_ordered_uuids
    array | null
  • only_count_matured_users
    boolean
  • update_feature_flag_params
    boolean
    Default: false
  • version
    integer | null
  • original_experiment
    object | null
  • tags
    array

Example request

POST /api/projects/:project_id/experiments/:id/duplicate
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/duplicate/\
-d name="string",\
-d feature_flag_key="string"

Example response

Status 200 No response body

Create experiments end

End a running experiment without shipping a variant.

Sets end_date to now and marks the experiment as stopped. The feature flag is NOT modified — users continue to see their assigned variants and exposure events ($feature_flag_called) continue to be recorded. However, only data up to end_date is included in experiment results.

Use this when:

  • You want to freeze the results window without changing which variant users see.
  • A variant was already shipped manually via the feature flag UI and the experiment just needs to be marked complete.

The end_date can be adjusted after ending via PATCH if it needs to be backdated (e.g. to match when the flag was actually paused).

Other options:

  • Use ship_variant to end the experiment AND roll out a single variant to 100%% of users.
  • Use pause to deactivate the flag without ending the experiment (stops variant assignment but does not freeze results).

Returns 400 if the experiment is not running.

Required API key scopes

experiment:write

Path parameters

  • id
    integer

Request parameters

  • conclusion
  • conclusion_comment
    string | null
  • open_cleanup_pr
    boolean
    Default: false
  • repository
    string | null
  • set_repository_as_team_default
    boolean
    Default: false

Response


Example request

POST /api/projects/:project_id/experiments/:id/end
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/end/\
-d conclusion=undefined

Example response

Status 200
RESPONSE
{
"id": 0,
"name": "string",
"description": "string",
"start_date": "2019-08-24T14:15:22Z",
"end_date": "2019-08-24T14:15:22Z",
"feature_flag_key": "string",
"feature_flag": {
"id": 0,
"team_id": 0,
"name": "string",
"key": "string",
"filters": {},
"deleted": true,
"active": true,
"ensure_experience_continuity": true,
"version": -2147483648,
"evaluation_runtime": "server",
"bucketing_identifier": "distinct_id",
"evaluation_contexts": [
"string"
]
},
"holdout": {
"id": 0,
"name": "string",
"description": "string",
"filters": [
{
"properties": [
{
"key": "string",
"type": "cohort",
"cohort_name": "string",
"group_type_index": 0,
"value": null,
"operator": "exact"
}
],
"rollout_percentage": 0.1,
"variant": "string",
"aggregation_group_type_index": 0
}
],
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"user_access_level": "string"
},
"holdout_id": 0,
"exposure_cohort": 0,
"parameters": {
"minimum_detectable_effect": null,
"variant_notes": null
},
"running_time_calculation": {
"exposure_estimate_config": null,
"minimum_detectable_effect": null,
"recommended_running_time": null,
"recommended_sample_size": null
},
"excluded_variants": [
"string"
],
"secondary_metrics": null,
"saved_metrics": [
{
"id": 0,
"experiment": 0,
"saved_metric": 0,
"metadata": null,
"created_at": "2019-08-24T14:15:22Z",
"query": null,
"name": "string",
"effective_query": {
"breakdownFilter": null,
"conversion_window": null,
"conversion_window_unit": null,
"fingerprint": null,
"goal": null,
"ignore_zeros": null,
"isSharedMetric": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "mean",
"name": null,
"response": null,
"sharedMetricId": null,
"source": {
"custom_name": null,
"event": null,
"fixedProperties": null,
"kind": "EventsNode",
"limit": null,
"math": null,
"math_group_type_index": null,
"math_hogql": null,
"math_multiplier": null,
"math_property": null,
"math_property_revenue_currency": null,
"math_property_type": null,
"name": null,
"optionalInFunnel": null,
"orderBy": null,
"properties": null,
"response": null,
"version": null
},
"threshold": null,
"upper_bound_percentile": null,
"uuid": null,
"version": null
}
}
],
"saved_metrics_ids": [
null
],
"filters": null,
"archived": false,
"deleted": true,
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"type": "web",
"exposure_criteria": {
"activation_config": null,
"exposure_config": null,
"filterTestAccounts": null,
"multiple_variant_handling": null
},
"metrics": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"metrics_secondary": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"stats_config": null,
"scheduling_config": null,
"allow_unknown_events": false,
"_create_in_folder": "string",
"conclusion": "won",
"conclusion_comment": "string",
"flag_cleanup_task_id": "72bdc9e1-c8bb-44f1-8473-a75871329c84",
"repository": "string",
"primary_metrics_ordered_uuids": [
"string"
],
"secondary_metrics_ordered_uuids": [
"string"
],
"only_count_matured_users": true,
"update_feature_flag_params": false,
"version": 0,
"original_experiment": {},
"status": "draft",
"is_legacy": true,
"can_freeze_exposure": true,
"resolved_exposure_event": "string",
"health": {
"findings": [
{
"code": "flag_off_while_running",
"subcode": "string",
"reason": "string",
"severity": "critical",
"title": "string",
"detail": "string",
"evidence": {
"property1": "string",
"property2": "string"
},
"actions": [
"open_feature_flag"
],
"diagnostic_ref": "string",
"check": "flag_state"
}
],
"checks": [
{
"key": "flag_state",
"name": "string",
"description": "string",
"status": "passed",
"reason": "string",
"values": {
"property1": "string",
"property2": "string"
},
"rule": {
"value": "exposed_count",
"threshold": 0.1,
"warns": "above",
"test": "chi_squared",
"minimum": {
"value": "exposed_count",
"threshold": 0.1
}
}
}
],
"setup": {
"release_conditions": [
{
"rollout_percentage": 0.1,
"property_count": 0,
"aggregation_group_type_index": 0
}
],
"early_exit": true,
"bucketing_identifier": "distinct_id",
"aggregation_group_type_index": 0,
"evaluation_runtime": "server",
"evaluation_contexts": [
"string"
],
"ensure_experience_continuity": true
}
},
"user_access_level": "string",
"tags": [
"string"
]
}

Retrieve experiments flag cleanup target

Repository a flag-cleanup pull request for this experiment would be opened in.

Resolution order: the experiment's saved repository, else the environment's default cleanup repository, else the team's only connected GitHub repository. When the team has several repositories and none is saved (source=ambiguous), pass one via repository on end/ship_variant.

Required API key scopes

experiment:read

Path parameters

  • id
    integer

Response


Example request

GET /api/projects/:project_id/experiments/:id/flag_cleanup_target
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/flag_cleanup_target/

Example response

Status 200
RESPONSE
{
"repository": "string",
"source": "explicit",
"candidates": [
"string"
]
}

Retrieve experiments flag cleanup task

Status of the flag-cleanup Desktop task opened for this experiment.

When an experiment was ended or shipped with open_cleanup_pr=true, a Desktop task removes the experiment's feature-flag code and opens a draft pull request. This returns that task's latest run status and the PR URL once one is opened. Poll until is_terminal is true. Returns 404 when no cleanup task was opened.

Required API key scopes

experiment:read

Path parameters

  • id
    integer

Response


Example request

GET /api/projects/:project_id/experiments/:id/flag_cleanup_task
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/flag_cleanup_task/

Example response

Status 200
RESPONSE
{
"task_id": "736fde4d-9029-4915-8189-01353d6982cb",
"run_status": "not_started",
"is_terminal": true,
"pr_url": "string",
"can_view_task": true
}

Create experiments freeze exposure

Freeze exposure on a running experiment while metrics keep flowing.

Snapshots the already-exposed users into a static cohort and narrows the linked feature flag so only those users keep matching — new users can no longer enter the experiment. end_date is left null so long-term metrics (revenue/LTV/renewals/retention) keep accumulating. Enrolled users keep their assigned variant. The serialized status becomes 'exposure_frozen'.

Returns 400 if the experiment is not running, exposure is already frozen, the experiment is group-aggregated (group flags cannot be frozen with a person cohort), or the exposed set is too large to snapshot synchronously.

Required API key scopes

experiment:write

Path parameters

  • id
    integer

Response


Example request

POST /api/projects/:project_id/experiments/:id/freeze_exposure
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/freeze_exposure/

Example response

Status 200
RESPONSE
{
"id": 0,
"name": "string",
"description": "string",
"start_date": "2019-08-24T14:15:22Z",
"end_date": "2019-08-24T14:15:22Z",
"feature_flag_key": "string",
"feature_flag": {
"id": 0,
"team_id": 0,
"name": "string",
"key": "string",
"filters": {},
"deleted": true,
"active": true,
"ensure_experience_continuity": true,
"version": -2147483648,
"evaluation_runtime": "server",
"bucketing_identifier": "distinct_id",
"evaluation_contexts": [
"string"
]
},
"holdout": {
"id": 0,
"name": "string",
"description": "string",
"filters": [
{
"properties": [
{
"key": "string",
"type": "cohort",
"cohort_name": "string",
"group_type_index": 0,
"value": null,
"operator": "exact"
}
],
"rollout_percentage": 0.1,
"variant": "string",
"aggregation_group_type_index": 0
}
],
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"user_access_level": "string"
},
"holdout_id": 0,
"exposure_cohort": 0,
"parameters": {
"minimum_detectable_effect": null,
"variant_notes": null
},
"running_time_calculation": {
"exposure_estimate_config": null,
"minimum_detectable_effect": null,
"recommended_running_time": null,
"recommended_sample_size": null
},
"excluded_variants": [
"string"
],
"secondary_metrics": null,
"saved_metrics": [
{
"id": 0,
"experiment": 0,
"saved_metric": 0,
"metadata": null,
"created_at": "2019-08-24T14:15:22Z",
"query": null,
"name": "string",
"effective_query": {
"breakdownFilter": null,
"conversion_window": null,
"conversion_window_unit": null,
"fingerprint": null,
"goal": null,
"ignore_zeros": null,
"isSharedMetric": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "mean",
"name": null,
"response": null,
"sharedMetricId": null,
"source": {
"custom_name": null,
"event": null,
"fixedProperties": null,
"kind": "EventsNode",
"limit": null,
"math": null,
"math_group_type_index": null,
"math_hogql": null,
"math_multiplier": null,
"math_property": null,
"math_property_revenue_currency": null,
"math_property_type": null,
"name": null,
"optionalInFunnel": null,
"orderBy": null,
"properties": null,
"response": null,
"version": null
},
"threshold": null,
"upper_bound_percentile": null,
"uuid": null,
"version": null
}
}
],
"saved_metrics_ids": [
null
],
"filters": null,
"archived": false,
"deleted": true,
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"type": "web",
"exposure_criteria": {
"activation_config": null,
"exposure_config": null,
"filterTestAccounts": null,
"multiple_variant_handling": null
},
"metrics": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"metrics_secondary": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"stats_config": null,
"scheduling_config": null,
"allow_unknown_events": false,
"_create_in_folder": "string",
"conclusion": "won",
"conclusion_comment": "string",
"flag_cleanup_task_id": "72bdc9e1-c8bb-44f1-8473-a75871329c84",
"repository": "string",
"primary_metrics_ordered_uuids": [
"string"
],
"secondary_metrics_ordered_uuids": [
"string"
],
"only_count_matured_users": true,
"update_feature_flag_params": false,
"version": 0,
"original_experiment": {},
"status": "draft",
"is_legacy": true,
"can_freeze_exposure": true,
"resolved_exposure_event": "string",
"health": {
"findings": [
{
"code": "flag_off_while_running",
"subcode": "string",
"reason": "string",
"severity": "critical",
"title": "string",
"detail": "string",
"evidence": {
"property1": "string",
"property2": "string"
},
"actions": [
"open_feature_flag"
],
"diagnostic_ref": "string",
"check": "flag_state"
}
],
"checks": [
{
"key": "flag_state",
"name": "string",
"description": "string",
"status": "passed",
"reason": "string",
"values": {
"property1": "string",
"property2": "string"
},
"rule": {
"value": "exposed_count",
"threshold": 0.1,
"warns": "above",
"test": "chi_squared",
"minimum": {
"value": "exposed_count",
"threshold": 0.1
}
}
}
],
"setup": {
"release_conditions": [
{
"rollout_percentage": 0.1,
"property_count": 0,
"aggregation_group_type_index": 0
}
],
"early_exit": true,
"bucketing_identifier": "distinct_id",
"aggregation_group_type_index": 0,
"evaluation_runtime": "server",
"evaluation_contexts": [
"string"
],
"ensure_experience_continuity": true
}
},
"user_access_level": "string",
"tags": [
"string"
]
}

Retrieve experiments health

Health check findings for this experiment: problems in its configuration and its feature flag that keep it from producing trustworthy results, each with a fix. checks gives the result of each check, so a check that found no problem can be told from one that did not apply or could not read an input.

The checks here read the experiment, its flag, its linked metrics, the project's event and property definitions, the cohorts of the exposure criteria, and the changes of the flag's variant split since launch. The checks that read exposure counts come with the exposure query. The split-change check compares the split changes with the exposures only for exposure criteria that name an event without property filters. When the split changed after launch and the criteria have filters or an action, or an API key lacks query:read, it returns an info finding with the subcode not_checked and the cause in reason. A caller who can't view the linked flag's history (viewer access to the flag and, with an API key, activity_log:read) gets that finding for every running experiment, because the changes are not read.

Two checks read whether the project received an event from its event definitions: a definition without last_seen_at, such as one Wizard wrote for a planned event, counts as not received. A name whose definition was deleted since launch, or in the last day for a draft, is not checked, because ingestion writes the definition again only when the event arrives. No missing definition is checked when ingestion saw none of the experiment's events in the last day, because ingestion can be set to skip a team. metric_event_not_ingested names each metric that reads an event the project never received, in the evidence keys metric_N, metric_N_role and metric_N_events. exposure_criteria_cannot_match reports a custom exposure event the project never received (exposure_event_not_ingested), a $feature_flag filter on the flag call events that requires another flag (filter_on_another_flag), and a filter on an event or person property that the project has no definition of, with an operator that a missing property fails (filter_on_property_not_ingested, the keys in evidence.properties). A property whose definition was ever deleted is not checked, and neither is an event property filter on an action or on $groupidentify, whose properties ingestion keeps no definitions of. An event or property not received is info before launch, in the first 24 hours after launch, and when only secondary metrics read it, and a warning otherwise. filter_on_another_flag is a warning in every state, filter_on_property_not_ingested also reports after the end, and the other findings stop at the end.

exposure_filters reads the cohort filters of the exposure criteria and of the activation, not the test account filters. exposure_filter_on_dynamic_cohort is a warning in every state: the results use the members of a dynamic cohort at the calculation, not at exposure. Its subcode is cohort_forces_variant when a release condition of the flag that matches the cohort's members gives one variant, cohort_in_release_conditions when the release conditions match its members otherwise, and evidence.cohort_ids names the cohorts. Both subcodes need the exposure criteria to keep the members too, not to leave them out.

metric_cannot_compile builds and compiles the query of each metric without running it, as the caller, so a metric that every calculation fails on shows before launch. A metric that reads a warehouse table or view the caller may not query is not checked for them. The finding names each failing metric in the evidence keys metric_N, metric_N_role, metric_N_error (the error class, which is also the subcode of the first metric) and metric_N_message (the compiler's message). It is a warning when a primary metric fails, also after the end, because the calculation after the fix reads the events up to the end. It is info otherwise. A failure inside ClickHouse, such as a type that the data holds, isn't found. A failing metric compiles again on every request. A metric that compiles is cached per caller for a day, so a cohort or table that is deleted after a compile can take up to a day to show.

metric_calculation_failed reports each metric whose latest calculation failed, from the latest finished calculation that the results page shows. It leaves out a metric that metric_cannot_compile reports. The subcode is the kind of the first failure: busy, query_limit (the query reached the read, memory, time or length limit), settings (a setting of the metric or the experiment), not_enough_data, experiment_too_old (the experiment started too long ago to calculate again) or unexpected_error. Each metric is in the evidence keys metric_N, metric_N_role, metric_N_failure (the kind), metric_N_error (the limit, or the family of a setting) and metric_N_message (only a message that PostHog wrote for users), and calculated_at is when the calculation finished. It is a warning when a primary metric fails for a kind that a change fixes (query_limit, settings, experiment_too_old), also after the end, because the calculation after the fix reads the events up to the end. It is info otherwise. When the first failure reached the read, memory or time limit, reason names the cause that the calculation shows: metric when another metric of the same calculation completed the same read of the exposures, or exposure_criteria when every metric reached a limit and an exposure or test account filter makes each query read all the properties of an event, person or group. evidence.properties then names the filters. A query that read precomputed exposures doesn't apply those filters, so it can't get exposure_criteria. It is null otherwise.

metric_all_zero reports a metric that reads zero in every variant, from the same latest finished calculation, so the results page shows "Not enough data yet" at any sample size. Each side of a ratio that is zero in every variant counts on its own. It reads the stored result and the project's event definitions, and no events. A primary metric needs 1,000 exposures in the result and 72 hours of data, because most zeros before that are outcomes that take time. A retention metric counts those hours from the start of its retention window. The subcode is the cause of the first metric: blank_event (an event with an empty name), event_stopped (the project last received the event before launch, while ingestion still records the project), outlier_bound (an upper outlier bound that is 0 while some exposures have a value) or null when none shows a cause. blank_event and outlier_bound also report a secondary metric, and need only 100 exposures and 12 hours of data, because they read 0 at any traffic. A bound on the largest value of the exposures can't be 0 while one has a value, so it is no cause. Neither is a bound on a metric with breakdowns, which gets one bound per breakdown group. Until the end, the check leaves out a metric that uses an event metric_event_not_ingested reports. Each metric, or side of a ratio, is in the evidence keys metric_N, metric_N_role, metric_N_side, metric_N_exposures and metric_N_cause. It is a warning for a primary metric. After the end it stays a warning only for a cause that a setting fixes, because the calculation after the fix reads the events up to the end. It is info otherwise.

The severity of the some_conditions_pinned finding follows the largest share that the users of the pinned release conditions make up among the users who got one variant from the flag, in the last 7 days, or since launch or the flag's last save if later. It reads the flag's calls that name the matched condition, not the experiment's exposure criteria: info up to 5%, warning above, and no finding under 1% when at least half of the calls that returned a variant name a condition. The finding is info when the share is unknown, and reason says why: not_measured (for example an API key without query:read, or a caller denied a flag call property), too_few_people (under 100), or evaluated_outside_flag_service (most calls come from local evaluation, a bootstrap or the caller's own assignment). A pin to a variant with 0% in the split adds an info, because that variant's results show only the pinned users, unless the experiment excludes the variant from the analysis.

Two findings say that the variants are assigned outside PostHog, as info. A running experiment whose flag has a 0% rollout gets assigned_outside_flag_service instead of running_but_no_rollout when 10 or more people got a variant from flag calls without a flag version that are no local evaluation, from an hour after the window starts. When every condition that includes users pins the variant whose key one property holds, assigned_by_property replaces all_conditions_pinned. When none of them includes everyone, so that every other user gets no variant, closed_to_matched_users replaces it, as a warning. A condition without filters, or with only filters that leave users out, includes everyone.

A draft whose flag has no recorded call gets the info new_flag_no_traffic. The record is the flag's last_called_at, which a periodic task updates, so it trails a call. The check reports not_checked when the organization's flag calls skip the events table, and when the project has no active flag, because the web SDK then requests no flags.

A running experiment whose flag is disabled gets paused_from_experiment, as info, when its latest pause or resume since launch is a pause of the experiment. Otherwise it gets running_but_flag_disabled, as a warning. A caller who can't view the linked flag's history gets the warning, because the pause is not read. A draft whose flag is already active with multiple variants gets not_started_but_multiple_variants_rolled_out as info. An ended experiment whose flag is still active with multiple variants gets no finding when another experiment on the flag is running or launched after the end. Otherwise it gets ended_flag_shared_with_draft as info when a draft experiment uses the flag, ended_but_multiple_variants_rolled_out as a warning when the flag's last_called_at is after the end and within the last 3 days, and ended_flag_not_called as info when it is not, from 3 days and an hour after the end, because last_called_at trails a call. Until then without such a call, or when the organization's flag calls can't be read, it gets ended_flag_calls_unknown as info.

A running experiment whose first primary metric is a funnel gets the info early_significance (subcode below_detectable_effect) when a significant variant's difference is smaller than the smallest difference its sample can detect, while that sample is below the one the running time estimate plans for the minimum detectable effect. It reads the metric's current stored result, the one the results page shows after its last calculation, and the running time calculator's formula.

A running experiment with only_count_matured_users on gets the info metrics_not_matured while it is younger than the conversion or retention window of every primary metric, because no user can count for those metrics until a window passes.

Required API key scopes

experiment:read

Path parameters

  • id
    integer

Response


Example request

GET /api/projects/:project_id/experiments/:id/health
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/health/

Example response

Status 200
RESPONSE
{
"findings": [
{
"code": "flag_off_while_running",
"subcode": "string",
"reason": "string",
"severity": "critical",
"title": "string",
"detail": "string",
"evidence": {
"property1": "string",
"property2": "string"
},
"actions": [
"open_feature_flag"
],
"diagnostic_ref": "string",
"check": "flag_state"
}
],
"checks": [
{
"key": "flag_state",
"name": "string",
"description": "string",
"status": "passed",
"reason": "string",
"values": {
"property1": "string",
"property2": "string"
},
"rule": {
"value": "exposed_count",
"threshold": 0.1,
"warns": "above",
"test": "chi_squared",
"minimum": {
"value": "exposed_count",
"threshold": 0.1
}
}
}
],
"setup": {
"release_conditions": [
{
"rollout_percentage": 0.1,
"property_count": 0,
"aggregation_group_type_index": 0
}
],
"early_exit": true,
"bucketing_identifier": "distinct_id",
"aggregation_group_type_index": 0,
"evaluation_runtime": "server",
"evaluation_contexts": [
"string"
],
"ensure_experience_continuity": true
}
}

Retrieve experiments health inputs

Staff only. The inputs that the health checks read for this reader, to debug why a finding shows or not: the context of the checks in health, the exposure query's answer that the exposure checks read, and facts about the project from the setup context's providers (the team's experiment defaults and which SDKs call flags). The exposure answer comes from the cache. When it is missing or stale, a calculation starts in the background and exposures.status says so.

Required API key scopes

experiment:read

Path parameters

  • id
    integer

Response


Example request

GET /api/projects/:project_id/experiments/:id/health_inputs
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/health_inputs/

Example response

Status 200
RESPONSE
{
"is_launched": true,
"is_running": true,
"has_ended": true,
"is_paused": true,
"archived": true,
"baseline_variant_key": "string",
"excluded_variant_keys": [
"string"
],
"primary_metric_count": 0,
"secondary_metric_count": 0,
"flag": {
"active": true,
"deleted": true,
"release_conditions": [
{
"number": 0,
"rollout_percentage": 0,
"property_count": 0,
"reachable": true,
"pinned_variant": "string"
}
],
"variants": [
{
"key": "string",
"rollout_percentage": 0
}
],
"split_text": "string"
},
"flag_last_called_at": "2019-08-24T14:15:22Z",
"flag_called": true,
"flag_called_during_run": true,
"flag_called_after_end": true,
"exposure_events": {
"custom_event": "string",
"required_flag_key": "string",
"variant_property": "string",
"activation": "string"
},
"events_received": {
"property1": true,
"property2": true
},
"metric_compiles": {
"metric_count": 0,
"unknown_count": 0,
"no_access_count": 0,
"exposure_query_fails": true,
"failures": [
{
"name": "string",
"role": "string",
"kind": "rejected",
"message": "string"
}
]
},
"latest_calculation": {
"finished_at": "2019-08-24T14:15:22Z",
"failures": [
{
"name": "string",
"role": "string",
"error_type": "string",
"step": "string",
"retriable": true,
"message": "string"
}
],
"hours_of_data": 0,
"zero_metrics": [
{
"name": "string",
"role": "string",
"exposures": 0,
"ratio_side": "string",
"stopped_events": [
"string"
]
}
]
},
"flag_history": {
"checked": true,
"not_checked_reason": "string",
"start_date": "2019-08-24T14:15:22Z",
"team_timezone": "string",
"changes": [
{
"kind": "split",
"changed_at": "2019-08-24T14:15:22Z",
"changed": "string",
"before": "string",
"after": "string",
"counted": true
}
],
"exposed_before_first": true,
"exposed_between": [
{
"kind": "split",
"question": "string",
"exposed": true
}
]
},
"condition_set_traffic_status": "read",
"condition_set_traffic": {
"since": "2019-08-24T14:15:22Z",
"team_timezone": "string",
"people_by_set": [
{
"condition_set": 0,
"people": 0
}
],
"calls": 0,
"remotely_evaluated_calls": 0,
"people_assigned_outside": 0
},
"reader_access": {
"can_read_flag_history": true,
"can_query_events": true,
"denied_event_properties": [
"string"
]
},
"exposures": {
"status": "ready",
"computed_at": "2019-08-24T14:15:22Z",
"totals": {
"total_exposures": {
"property1": 0,
"property2": 0
},
"multiple_variant_handling": "string",
"sample_ratio_mismatch_p_value": 0,
"hours_since_launch": 0
},
"findings": [
{
"code": "flag_off_while_running",
"subcode": "string",
"reason": "string",
"severity": "critical",
"title": "string",
"detail": "string",
"evidence": {
"property1": "string",
"property2": "string"
},
"actions": [
"open_feature_flag"
],
"diagnostic_ref": "string",
"check": "flag_state"
}
],
"error": "string"
},
"project": {
"team_defaults": {
"status": "ok",
"data": {
"stats_method": "string",
"confidence_level": 0,
"minimum_detectable_effect": 0,
"product_default_minimum_detectable_effect": 0,
"product_default_stats_method": "string",
"product_default_confidence_level": 0.1,
"only_count_matured_users": true,
"cuped_enabled": true,
"sequential_testing_enabled": true,
"flags_persistence_default": true,
"test_account_filter_count": 0,
"new_experiments_filter_test_accounts": true,
"default_exposure_event": "string"
}
},
"sdk_profile": {
"status": "ok",
"data": {
"window_days": 0,
"source_event": "string",
"computed_at": "2019-08-24T14:15:22Z",
"libs": [
{
"lib": "string",
"category": "web",
"calls": 0,
"distinct_ids": 0,
"device_id_share": 0.1,
"locally_evaluated_share": 0,
"anonymous_share": 0
}
],
"libs_truncated": true,
"flags_seen": 0,
"flags_evaluated_on_server_and_web": 0,
"evaluated_on_server_and_web": true,
"libs_on_any_event": [
{
"lib": "string",
"category": "web",
"events": 0,
"distinct_ids": 0
}
],
"libs_on_any_event_truncated": true
}
}
}
}

Retrieve experiments in session exposure

How the recordings tab's in-session exposure scope reads on this experiment.

Resolved through the same seam as the recordings query's in_session refusal, so the scope control disables exactly what a query would be refused for, and the copy can say when sessions are matched on the stamped flag property rather than on the exposure event. Postgres reads only, so it can serve the tab's mount path.

Required API key scopes

experiment:read

Path parameters

  • id
    integer

Response


Example request

GET /api/projects/:project_id/experiments/:id/in_session_exposure
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/in_session_exposure/

Example response

Status 200
RESPONSE
{
"available": true,
"unavailable_reason": "string",
"uses_stamped_fallback": true
}

Create experiments launch

Launch a draft experiment.

Validates the experiment is in draft state, activates its linked feature flag, sets start_date to the current server time, and transitions the experiment to running. Returns 400 if the experiment has already been launched or if the feature flag configuration is invalid (e.g. fewer than 2 variants).

Required API key scopes

experiment:write

Path parameters

  • id
    integer

Response


Example request

POST /api/projects/:project_id/experiments/:id/launch
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/launch/

Example response

Status 200
RESPONSE
{
"id": 0,
"name": "string",
"description": "string",
"start_date": "2019-08-24T14:15:22Z",
"end_date": "2019-08-24T14:15:22Z",
"feature_flag_key": "string",
"feature_flag": {
"id": 0,
"team_id": 0,
"name": "string",
"key": "string",
"filters": {},
"deleted": true,
"active": true,
"ensure_experience_continuity": true,
"version": -2147483648,
"evaluation_runtime": "server",
"bucketing_identifier": "distinct_id",
"evaluation_contexts": [
"string"
]
},
"holdout": {
"id": 0,
"name": "string",
"description": "string",
"filters": [
{
"properties": [
{
"key": "string",
"type": "cohort",
"cohort_name": "string",
"group_type_index": 0,
"value": null,
"operator": "exact"
}
],
"rollout_percentage": 0.1,
"variant": "string",
"aggregation_group_type_index": 0
}
],
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"user_access_level": "string"
},
"holdout_id": 0,
"exposure_cohort": 0,
"parameters": {
"minimum_detectable_effect": null,
"variant_notes": null
},
"running_time_calculation": {
"exposure_estimate_config": null,
"minimum_detectable_effect": null,
"recommended_running_time": null,
"recommended_sample_size": null
},
"excluded_variants": [
"string"
],
"secondary_metrics": null,
"saved_metrics": [
{
"id": 0,
"experiment": 0,
"saved_metric": 0,
"metadata": null,
"created_at": "2019-08-24T14:15:22Z",
"query": null,
"name": "string",
"effective_query": {
"breakdownFilter": null,
"conversion_window": null,
"conversion_window_unit": null,
"fingerprint": null,
"goal": null,
"ignore_zeros": null,
"isSharedMetric": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "mean",
"name": null,
"response": null,
"sharedMetricId": null,
"source": {
"custom_name": null,
"event": null,
"fixedProperties": null,
"kind": "EventsNode",
"limit": null,
"math": null,
"math_group_type_index": null,
"math_hogql": null,
"math_multiplier": null,
"math_property": null,
"math_property_revenue_currency": null,
"math_property_type": null,
"name": null,
"optionalInFunnel": null,
"orderBy": null,
"properties": null,
"response": null,
"version": null
},
"threshold": null,
"upper_bound_percentile": null,
"uuid": null,
"version": null
}
}
],
"saved_metrics_ids": [
null
],
"filters": null,
"archived": false,
"deleted": true,
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"type": "web",
"exposure_criteria": {
"activation_config": null,
"exposure_config": null,
"filterTestAccounts": null,
"multiple_variant_handling": null
},
"metrics": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"metrics_secondary": [
{
"breakdownAttributionType": null,
"breakdownAttributionValue": null,
"breakdownFilter": null,
"completion_event": null,
"conversion_window": null,
"conversion_window_unit": null,
"denominator": null,
"denominator_outlier_handling": null,
"funnel_order_type": null,
"goal": null,
"ignore_zeros": null,
"kind": "ExperimentMetric",
"lower_bound_percentile": null,
"metric_type": "funnel",
"name": null,
"numerator": null,
"numerator_outlier_handling": null,
"retention_window_end": null,
"retention_window_start": null,
"retention_window_unit": null,
"series": null,
"source": null,
"start_event": null,
"start_handling": null,
"threshold": null,
"upper_bound_percentile": null,
"uuid": null
}
],
"stats_config": null,
"scheduling_config": null,
"allow_unknown_events": false,
"_create_in_folder": "string",
"conclusion": "won",
"conclusion_comment": "string",
"flag_cleanup_task_id": "72bdc9e1-c8bb-44f1-8473-a75871329c84",
"repository": "string",
"primary_metrics_ordered_uuids": [
"string"
],
"secondary_metrics_ordered_uuids": [
"string"
],
"only_count_matured_users": true,
"update_feature_flag_params": false,
"version": 0,
"original_experiment": {},
"status": "draft",
"is_legacy": true,
"can_freeze_exposure": true,
"resolved_exposure_event": "string",
"health": {
"findings": [
{
"code": "flag_off_while_running",
"subcode": "string",
"reason": "string",
"severity": "critical",
"title": "string",
"detail": "string",
"evidence": {
"property1": "string",
"property2": "string"
},
"actions": [
"open_feature_flag"
],
"diagnostic_ref": "string",
"check": "flag_state"
}
],
"checks": [
{
"key": "flag_state",
"name": "string",
"description": "string",
"status": "passed",
"reason": "string",
"values": {
"property1": "string",
"property2": "string"
},
"rule": {
"value": "exposed_count",
"threshold": 0.1,
"warns": "above",
"test": "chi_squared",
"minimum": {
"value": "exposed_count",
"threshold": 0.1
}
}
}
],
"setup": {
"release_conditions": [
{
"rollout_percentage": 0.1,
"property_count": 0,
"aggregation_group_type_index": 0
}
],
"early_exit": true,
"bucketing_identifier": "distinct_id",
"aggregation_group_type_index": 0,
"evaluation_runtime": "server",
"evaluation_contexts": [
"string"
],
"ensure_experience_continuity": true
}
},
"user_access_level": "string",
"tags": [
"string"
]
}

Create experiments metrics recalculation

Trigger a batch recalculation of all metrics for this experiment.

Returns 201 with the new pending recalculation, or 200 with the active one if a recalculation is already pending or in progress for this experiment. An experiment that started too long ago gets 201 with a run that is already failed: every metric carries the recalculation_window_too_long error in metric_errors, no workflow starts, and a retry gets the same answer. A manual trigger within five minutes after the latest completed run finished returns 429 with a Retry-After header. The response payload intentionally does not include the results array — at POST time the workflow has just been queued and no per-metric results exist yet. Clients should poll GET metrics_recalculation/{id}/ for results as the workflow progresses.

Required API key scopes

experiment:write

Path parameters

  • id
    integer

Request parameters

  • trigger
    Default: manual

Response


Example request

POST /api/projects/:project_id/experiments/:id/metrics_recalculation
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/experiments/:id/metrics_recalculation/\
-d trigger=undefined

Example response

Status 200
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"experiment_id": 0,
"status": "pending",
"total_metrics": 0,
"completed_metrics": 0,
"failed_metrics": 0,
"metric_errors": null,
"created_at": "2019-08-24T14:15:22Z",
"started_at": "2019-08-24T14:15:22Z",
"completed_at": "2019-08-24T14:15:22Z",
"query_to": "2019-08-24T14:15:22Z",
"is_existing": true
}
Status 201
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"experiment_id": 0,
"status": "pending",
"total_metrics": 0,
"completed_metrics": 0,
"failed_metrics": 0,
"metric_errors": null,
"created_at": "2019-08-24T14:15:22Z",
"started_at": "2019-08-24T14:15:22Z",
"completed_at": "2019-08-24T14:15:22Z",
"query_to": "2019-08-24T14:15:22Z",
"is_existing": true
}
Status 429 A manual trigger arrived less than five minutes after the latest completed run finished. Retry-After carries the seconds until the next run is allowed.