Vision

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

Endpoints

POST
GET
GET
POST
POST
POST
GET
POST
GET

Create vision scanners scouts

Create a scout that watches this scanner, recorded as belonging to it.

Required API key scopes

replay_scanner:writesession_recording:readllm_skill:writesignal_scout:write

Path parameters

  • scanner_id
    string

Request parameters

  • display_name
    string
  • name
    string
  • description
    string
  • body
    string
  • config
  • variant_analysis
    boolean
    Default: false

Response


Example request

POST /api/projects/:project_id/vision/scanners/:scanner_id/scouts
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/vision/scanners/:scanner_id/scouts/\
-d description="string",\
-d body="string"

Example response

Status 200 The scout already existed; the supplied config was applied.
RESPONSE
{
"created": true,
"config": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"skill_name": "string",
"description": "string",
"display_name": "string",
"scout_origin": "canonical",
"scout_role": "specialist",
"deprecation": {
"phase": "announced",
"reason": "string",
"superseded_by": "string",
"sunset_at": "2019-08-24T14:15:22Z"
},
"owners": [
{
"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"
}
],
"enabled": true,
"status": "active",
"pause_reason": "no_output",
"managed_by": "team",
"emit": true,
"run_interval_minutes": 30,
"run_cron_schedule": "string",
"output_destinations": {
"slack": {
"integration_id": 1,
"channel": "string",
"users": [
"string"
],
"thread_reports": true
},
"webhook": {
"hog_function_id": "string"
},
"inbox": true
},
"structured_output_schema": {},
"network_access": "trusted",
"model": "string",
"mcp_gateway_server_ids": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
],
"repositories": [
"string"
],
"write_scopes": [
"string"
],
"lifecycle_locked": true,
"allowed_mcp_tools": [
"string"
],
"tool_preset": "string",
"precheck_query": "string",
"precheck_disabled": true,
"effective_precheck_query": "string",
"precheck_query_source": "config",
"last_precheck_at": "2019-08-24T14:15:22Z",
"last_precheck_outcome": "run",
"last_precheck_row_count": 0,
"last_run_at": "2019-08-24T14:15:22Z",
"consecutive_failure_count": 0,
"status_changed_at": "2019-08-24T14:15:22Z",
"status_changed_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"
},
"auto_pause_exempt": true,
"tags": [
"string"
],
"source_product": "string",
"source_id": "string",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}
}
Status 201 The scout and its config were created.
RESPONSE
{
"created": true,
"config": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"skill_name": "string",
"description": "string",
"display_name": "string",
"scout_origin": "canonical",
"scout_role": "specialist",
"deprecation": {
"phase": "announced",
"reason": "string",
"superseded_by": "string",
"sunset_at": "2019-08-24T14:15:22Z"
},
"owners": [
{
"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"
}
],
"enabled": true,
"status": "active",
"pause_reason": "no_output",
"managed_by": "team",
"emit": true,
"run_interval_minutes": 30,
"run_cron_schedule": "string",
"output_destinations": {
"slack": {
"integration_id": 1,
"channel": "string",
"users": [
"string"
],
"thread_reports": true
},
"webhook": {
"hog_function_id": "string"
},
"inbox": true
},
"structured_output_schema": {},
"network_access": "trusted",
"model": "string",
"mcp_gateway_server_ids": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
],
"repositories": [
"string"
],
"write_scopes": [
"string"
],
"lifecycle_locked": true,
"allowed_mcp_tools": [
"string"
],
"tool_preset": "string",
"precheck_query": "string",
"precheck_disabled": true,
"effective_precheck_query": "string",
"precheck_query_source": "config",
"last_precheck_at": "2019-08-24T14:15:22Z",
"last_precheck_outcome": "run",
"last_precheck_row_count": 0,
"last_run_at": "2019-08-24T14:15:22Z",
"consecutive_failure_count": 0,
"status_changed_at": "2019-08-24T14:15:22Z",
"status_changed_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"
},
"auto_pause_exempt": true,
"tags": [
"string"
],
"source_product": "string",
"source_id": "string",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}
}
Status 403 The caller may not edit this scanner.

List all vision scanners variants

Per-variant readout for an experiment scanner: observation counts, distinct people, median session length, sampling rate and latest observations per variant, read live, plus the digests and differences of the scanner's variant analysis scout.

Required API key scopes

replay_scanner:readsession_recording:read

Path parameters

  • scanner_id
    string

Response


Example request

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

Example response

Status 200
RESPONSE
{
"experiment": {
"id": 0,
"name": "string",
"status": "string",
"start_date": "2019-08-24T14:15:22Z",
"end_date": "2019-08-24T14:15:22Z",
"planned_duration_days": 0,
"current_day": 0
},
"window": {
"total_observations": 0,
"first_observation_at": "2019-08-24T14:15:22Z",
"last_observation_at": "2019-08-24T14:15:22Z"
},
"variants": [
{
"key": "string",
"observations": 0,
"distinct_people": 0,
"median_session_duration_s": 0,
"sampling_rate": 0,
"analysis_observations": 0,
"digest": [
{
"theme": "string",
"statement": "string",
"count": 0,
"read": 0,
"example_observation_ids": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}
],
"latest_observations": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"scanner_id": "43593f58-da3f-45f0-a7bf-8763ef29bdf1",
"scanner_origin": "configured",
"session_id": "string",
"status": "pending",
"error_reason": "string",
"workflow_id": "string",
"scanner_snapshot": {
"name": "string",
"scanner_type": "monitor",
"scanner_version": 0,
"model": "string",
"provider": "string",
"emits_signals": true,
"scanner_config": null,
"variant_sampling_rates": {
"property1": 0.1,
"property2": 0.1
}
},
"scanner_result": {
"model_output": null,
"signals_count": 0,
"experiment_variant": "string",
"session_duration_s": 0
},
"prompt_question": "string",
"prompt_valence": "good",
"triggered_by": "schedule",
"triggered_by_user": {
"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"
},
"backfill_id": "724334b4-c968-4355-bf48-120b6dce0c58",
"distinct_id": "string",
"recording_subject_email": "string",
"previous_observation_id": "bdc4be48-ad44-4150-aaf7-80ca533d4bac",
"next_observation_id": "67a517e1-9b1d-4c86-8d8e-6ec9b5738f26",
"label": {
"is_correct": true,
"feedback": ""
},
"viewed": true,
"media": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"kind": "thumbnail",
"position": 0,
"asset_id": 0,
"video_start_ms": 0
}
],
"summary_line": "string",
"started_at": "2019-08-24T14:15:22Z",
"completed_at": "2019-08-24T14:15:22Z",
"created_at": "2019-08-24T14:15:22Z"
}
]
}
],
"differences": [
{
"theme": "string",
"statement": "string",
"counts": {
"property1": 0,
"property2": 0
},
"read": {
"property1": 0,
"property2": 0
}
}
],
"unattributed_count": 0,
"analysis": {
"scout_config_id": "string",
"scout_enabled": true,
"recorded_at": "2019-08-24T14:15:22Z",
"scanner_version": 0,
"current": true
}
}
Status 400 The scanner is not an experiment scanner.

Retrieve vision scanners creators

Distinct creators across the team's scanners — feeds the Created by filter dropdown.

Required API key scopes

replay_scanner:read

Response


Example request

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

Example response

Status 200
RESPONSE
{
"creators": [
{
"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"
}
]
}

Create vision scanners draft

Draft a full scanner configuration from a natural-language goal and a monthly credit budget.

Required API key scopes

replay_scanner:writesession_recording:read

Request parameters

  • goal
    string
  • monthly_credit_budget
    integer
  • free_only
    boolean
    Default: false
  • experiment_id
    integer

Response


Example request

POST /api/projects/:project_id/vision/scanners/draft
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/vision/scanners/draft/\
-d goal="string"

Example response

Status 200
RESPONSE
{
"name": "string",
"description": "string",
"scanner_type": "monitor",
"scanner_config": null,
"rationale": "string",
"query": null,
"sampling_mode": "focused",
"sampling_rate": 0,
"model": "gemini-3.5-flash-lite",
"credit_limit": 0,
"free_only": true,
"estimated_monthly_observations": 0
}
Status 400 The goal is missing or AI consent hasn't been granted.
RESPONSE
{
"detail": "string"
}
Status 403 The caller lacks the required access, or the feature isn't enabled.
RESPONSE
{
"detail": "string"
}
Status 503 The draft couldn't be generated.
RESPONSE
{
"detail": "string"
}

Create vision scanners estimate

Estimate the observation volume a proposed scanner would generate, for the pre-save cost preview.

Required API key scopes

replay_scanner:readsession_recording:read

Request parameters

  • query
  • sampling_rate
    number
    Default: 1
  • sampling_mode
    Default: comprehensive
  • scanner_id
    string | null
  • model
    Default: gemini-3-flash-preview
  • experiment_targeting
  • experiment

Response


Example request

POST /api/projects/:project_id/vision/scanners/estimate
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/vision/scanners/estimate/\
-d query=undefined

Example response

Status 200
RESPONSE
{
"matched_sessions_in_window": 0,
"window_days": 0,
"estimated_observations_per_month": 0,
"credits_per_observation": 0,
"estimated_credits_per_month": 0,
"other_enabled_scanners_monthly_credits": 0,
"active_backfill_credits": 0,
"free_only_monthly_credits_left": 0,
"sampling_rate": 0.1
}

Create vision scanners inline scan

Scan named sessions against a prompt without saving a scanner first, for one-off questions.

The config resolves to a scanner minted on first use, so asking the same question twice reuses the observations it already has, while a different question about the same session gets its own.

With scanner_type set to summarizer, this is how you get PostHog's own AI summary for a recording ID. It resolves to the Summarize button's own scanner only when the prompt and scanner_config match what the button sends, since the config is what the key fingerprints.

Required API key scopes

replay_scanner:writesession_recording:read

Request parameters

  • built_in
  • prompt
    string
  • scanner_type
  • scanner_config
  • model
    Default: gemini-3-flash-preview
  • session_ids
    array

Response


Example request

POST /api/projects/:project_id/vision/scanners/inline_scan
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/vision/scanners/inline_scan/\
-d session_ids="array"

Example response

Status 202
RESPONSE
{
"started": 0,
"results": [
{
"session_id": "string",
"scan_outcome": "started"
}
],
"scan_id": "9a59f0f5-5572-476d-a7fc-c960ef43a5af"
}

Retrieve vision scanners stats

Team-wide scanner counts — independent of list filters, so the overview stays stable.

Required API key scopes

replay_scanner:read

Response


Example request

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

Example response

Status 200
RESPONSE
{
"total": 0,
"enabled": 0,
"by_type": {
"monitor": {
"enabled": 0,
"total": 0
},
"classifier": {
"enabled": 0,
"total": 0
},
"scorer": {
"enabled": 0,
"total": 0
},
"summarizer": {
"enabled": 0,
"total": 0
},
"experiment": {
"enabled": 0,
"total": 0
}
}
}

Create vision scanners suggest tags

Suggest classifier tags grounded in the scanner's own observations and the org's product data.

Required API key scopes

replay_scanner:readsession_recording:read

Request parameters

  • prompt
    string
  • tags
    array
  • multi_label
    boolean
    Default: true
  • allow_freeform_tags
    boolean
    Default: false
  • scanner_id
    string | null

Response


Example request

POST /api/projects/:project_id/vision/scanners/suggest_tags
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/vision/scanners/suggest_tags/\
-d prompt="string"

Example response

Status 200
RESPONSE
{
"suggestions": [
{
"tag": "string",
"rationale": "string",
"source": "observed"
}
]
}
Status 503 Tag suggestions couldn't be generated.
RESPONSE
{
"detail": "string"
}

Retrieve vision scanners watch feed

Succeeded observations in the window worth watching, ranked — feeds the What to watch tab.

Required API key scopes

replay_scanner:readsession_recording:read

Query parameters

  • created_by
    string
  • date_from
    string
    Default: -7d
  • date_to
    string
  • limit
    integer
    Default: 20
  • scanner_ids
    string
  • scanner_type
    string
    One of: "monitor""classifier""scorer""summarizer""experiment"
  • search
    string
  • tags
    string

Response


Example request

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

Example response

Status 200
RESPONSE
{
"results": [
{
"observation": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"scanner_id": "43593f58-da3f-45f0-a7bf-8763ef29bdf1",
"scanner_origin": "configured",
"session_id": "string",
"status": "pending",
"error_reason": "string",
"workflow_id": "string",
"scanner_snapshot": {
"name": "string",
"scanner_type": "monitor",
"scanner_version": 0,
"model": "string",
"provider": "string",
"emits_signals": true,
"scanner_config": null,
"variant_sampling_rates": {
"property1": 0.1,
"property2": 0.1
}
},
"scanner_result": {
"model_output": null,
"signals_count": 0,
"experiment_variant": "string",
"session_duration_s": 0
},
"prompt_question": "string",
"prompt_valence": "good",
"triggered_by": "schedule",
"triggered_by_user": {
"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"
},
"backfill_id": "724334b4-c968-4355-bf48-120b6dce0c58",
"distinct_id": "string",
"recording_subject_email": "string",
"previous_observation_id": "bdc4be48-ad44-4150-aaf7-80ca533d4bac",
"next_observation_id": "67a517e1-9b1d-4c86-8d8e-6ec9b5738f26",
"label": {
"is_correct": true,
"feedback": ""
},
"viewed": true,
"media": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"kind": "thumbnail",
"position": 0,
"asset_id": 0,
"video_start_ms": 0
}
],
"summary_line": "string",
"started_at": "2019-08-24T14:15:22Z",
"completed_at": "2019-08-24T14:15:22Z",
"created_at": "2019-08-24T14:15:22Z"
},
"reason": {
"kind": "signal_emitted",
"signals_count": 0,
"problem_types": [
"string"
],
"signals": [
{
"problem_type": "string",
"headline": "string"
}
],
"verdict": "string",
"verdict_share": 0,
"notability": 0,
"jev_probability": 0,
"notability_reason": "string",
"watch_reason": "visible_error",
"score": 0,
"window_mean": 0,
"tag": "string",
"tag_share": 0
}
}
],
"ranker": "weighted-score",
"ranker_variant": "string"
}