Visual

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

Endpoints

POST
POST
GET
POST
POST
GET
GET
POST
GET
GET

Create visual review runs finalize

Finalize a fully-reviewed run: commit the approved baseline and green the gate.

Commits exactly the snapshots approved in the DB (tolerated ones keep their baseline) and only succeeds once every changed/new snapshot is resolved. With approve_all=true, any still-pending changed/new snapshot is approved first; quarantined snapshots are skipped, but a quarantined snapshot approved by identifier is still committed. With commit_to_github=false the server returns the signed baseline YAML instead of committing it.

Required API key scopes

visual_review:write

Path parameters

  • id
    string

Request parameters

  • approve_all
    boolean
    Default: false
  • commit_to_github
    boolean
    Default: true
  • add_images_to_comment_on_pr
    boolean
    Default: false

Response


Example request

POST /api/projects/:project_id/visual_review/runs/:id/finalize
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/visual_review/runs/:id/finalize/\
-d approve_all="boolean"

Example response

Status 200
RESPONSE
{
"run": {
"approved_by": {
"id": 0,
"first_name": "string",
"email": "string"
},
"purpose": "review",
"search_match_type": "exact",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"repo_id": "59e69ce7-60be-4408-9333-ec12132fc070",
"status": "string",
"run_type": "string",
"commit_sha": "string",
"branch": "string",
"pr_number": 0,
"approved": true,
"approved_at": "2019-08-24T14:15:22Z",
"summary": {
"total": 0,
"changed": 0,
"new": 0,
"removed": 0,
"unchanged": 0,
"unresolved": 0,
"tolerated_matched": 0
},
"error_message": "string",
"created_at": "2019-08-24T14:15:22Z",
"completed_at": "2019-08-24T14:15:22Z",
"is_stale": true,
"superseded_by_id": "6b86439a-ba84-4137-9924-cffddd52399a",
"metadata": {}
},
"baseline_content": "string"
}

Create visual review runs lift on merge

Lift a quarantined snapshot's quarantine once this run's pull request merges. The lift applies only after a default-branch run that contains the merge renders the expected picture, and the baseline entry holds that same picture. Requesting a lift never approves a picture: approve a changed or new snapshot by identifier first. Requesting again from the same pull request replaces the pending request.

Required API key scopes

visual_review:write

Path parameters

  • id
    string

Request parameters

  • identifier
    string

Response


Example request

POST /api/projects/:project_id/visual_review/runs/:id/lift_on_merge
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/visual_review/runs/:id/lift_on_merge/\
-d identifier="string"

Example response

Status 201
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"quarantine_id": "b1c487a8-98e2-4390-8dfa-cb8015f5e43a",
"identifier": "string",
"run_type": "string",
"pr_number": 0,
"expected_hash": "string",
"state": "pending",
"detail": "string",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"resolved_at": "2019-08-24T14:15:22Z",
"source_run_id": "51116a97-0041-4601-85fc-eb599c2885fb",
"requested_by": {
"id": 0,
"first_name": "string",
"email": "string"
},
"merge_commit_sha": "string",
"lifted_at_sha": "string",
"source": "string"
}

List all visual review runs quarantine lifts

Every request to lift a quarantine when this run's pull request merges, newest first, in any state. Empty for a run without a pull request.

Required API key scopes

visual_review:read

Path parameters

  • id
    string

Example request

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

Example response

Status 200
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"quarantine_id": "b1c487a8-98e2-4390-8dfa-cb8015f5e43a",
"identifier": "string",
"run_type": "string",
"pr_number": 0,
"expected_hash": "string",
"state": "pending",
"detail": "string",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"resolved_at": "2019-08-24T14:15:22Z",
"source_run_id": "51116a97-0041-4601-85fc-eb599c2885fb",
"requested_by": {
"id": 0,
"first_name": "string",
"email": "string"
},
"merge_commit_sha": "string",
"lifted_at_sha": "string",
"source": "string"
}

Create visual review runs quarantine lifts cancel

Withdraw a pending request to lift a quarantine when this run's pull request merges.

Required API key scopes

visual_review:write

Path parameters

  • id
    string
  • request_id
    string

Example request

POST /api/projects/:project_id/visual_review/runs/:id/quarantine_lifts/:request_id/cancel
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/visual_review/runs/:id/quarantine_lifts/:request_id/cancel/

Example response

Status 204 No response body

Create visual review runs recompute

Re-evaluate quarantine and counts, update commit status, and optionally rerun the CI job.

Required API key scopes

visual_review:write

Path parameters

  • id
    string

Response


Example request

POST /api/projects/:project_id/visual_review/runs/:id/recompute
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/visual_review/runs/:id/recompute/

Example response

Status 200
RESPONSE
{
"run": {
"approved_by": {
"id": 0,
"first_name": "string",
"email": "string"
},
"purpose": "review",
"search_match_type": "exact",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"repo_id": "59e69ce7-60be-4408-9333-ec12132fc070",
"status": "string",
"run_type": "string",
"commit_sha": "string",
"branch": "string",
"pr_number": 0,
"approved": true,
"approved_at": "2019-08-24T14:15:22Z",
"summary": {
"total": 0,
"changed": 0,
"new": 0,
"removed": 0,
"unchanged": 0,
"unresolved": 0,
"tolerated_matched": 0
},
"error_message": "string",
"created_at": "2019-08-24T14:15:22Z",
"completed_at": "2019-08-24T14:15:22Z",
"is_stale": true,
"superseded_by_id": "6b86439a-ba84-4137-9924-cffddd52399a",
"metadata": {}
},
"counts_changed": true,
"unresolved": 0,
"ci_rerun_triggered": true,
"ci_rerun_error": "string"
}

List all visual review runs snapshot history

Also available via the PostHog MCP server:

  • visual-review-runs-snapshot-history-list — Snapshot change history

Recent change history for a snapshot identifier across runs.

Required API key scopes

visual_review:read

Path parameters

  • id
    string

Query parameters

  • identifier
    string
  • limit
    integer
  • offset
    integer

Response


Example request

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

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": [
{
"current_artifact": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"content_hash": "string",
"width": 0,
"height": 0,
"download_url": "string"
},
"row_shift": {
"bands": [
{
"y": 0,
"rows": 0,
"kind": "inserted"
}
],
"inserted_rows": 0,
"deleted_rows": 0,
"residual_percentage": 0.1,
"raw_diff_percentage": 0.1
},
"run_id": "dded282c-8ebd-44cf-8ba5-9a234973d1ec",
"snapshot_id": "163831af-8c1b-4992-a9cf-88c6306604c0",
"result": "string",
"branch": "string",
"commit_sha": "string",
"created_at": "2019-08-24T14:15:22Z",
"pr_number": 0,
"diff_percentage": 0,
"review_state": "string",
"ssim_score": 0,
"change_kind": "string",
"size_mismatch": true
}
]
}

List all visual review runs snapshots

Also available via the PostHog MCP server:

  • visual-review-runs-snapshots-list — List run snapshots

Get a run's snapshots with diff results, excluding quarantined ones by default.

Required API key scopes

visual_review:read

Path parameters

  • id
    string

Query parameters

  • exclude_unchanged
    boolean
    Default: false
  • include_quarantined
    boolean
    Default: false
  • limit
    integer
  • offset
    integer
  • quarantined_only
    boolean
    Default: false
  • snapshot_id
    string

Response


Example request

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

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": [
{
"current_artifact": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"content_hash": "string",
"width": 0,
"height": 0,
"download_url": "string"
},
"baseline_artifact": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"content_hash": "string",
"width": 0,
"height": 0,
"download_url": "string"
},
"diff_artifact": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"content_hash": "string",
"width": 0,
"height": 0,
"download_url": "string"
},
"reviewed_by": {
"id": 0,
"first_name": "string",
"email": "string"
},
"cluster_summary": {
"items": [
{
"x": 0,
"y": 0,
"width": 0,
"height": 0,
"pixel_count": 0,
"centroid_x": 0.1,
"centroid_y": 0.1
}
],
"total": 0,
"truncated": true
},
"row_shift": {
"bands": [
{
"y": 0,
"rows": 0,
"kind": "inserted"
}
],
"inserted_rows": 0,
"deleted_rows": 0,
"residual_percentage": 0.1,
"raw_diff_percentage": 0.1
},
"is_quarantined": true,
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"run_id": "dded282c-8ebd-44cf-8ba5-9a234973d1ec",
"identifier": "string",
"result": "string",
"classification_reason": "string",
"diff_percentage": 0,
"diff_pixel_count": 0,
"review_state": "string",
"reviewed_at": "2019-08-24T14:15:22Z",
"approved_hash": "string",
"tolerated_hash_id": "7019d9c2-0d1d-41e9-a8a2-90206607b139",
"metadata": {},
"ssim_score": 0,
"change_kind": "string",
"size_mismatch": true
}
],
"quarantined_count": 0
}

Create visual review runs tolerate

Mark a changed snapshot as a known tolerated alternate.

Required API key scopes

visual_review:write

Path parameters

  • id
    string

Request parameters

  • snapshot_id
    string

Response


Example request

POST /api/projects/:project_id/visual_review/runs/:id/tolerate
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/visual_review/runs/:id/tolerate/\
-d snapshot_id="string"

Example response

Status 200
RESPONSE
{
"current_artifact": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"content_hash": "string",
"width": 0,
"height": 0,
"download_url": "string"
},
"baseline_artifact": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"content_hash": "string",
"width": 0,
"height": 0,
"download_url": "string"
},
"diff_artifact": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"content_hash": "string",
"width": 0,
"height": 0,
"download_url": "string"
},
"reviewed_by": {
"id": 0,
"first_name": "string",
"email": "string"
},
"cluster_summary": {
"items": [
{
"x": 0,
"y": 0,
"width": 0,
"height": 0,
"pixel_count": 0,
"centroid_x": 0.1,
"centroid_y": 0.1
}
],
"total": 0,
"truncated": true
},
"row_shift": {
"bands": [
{
"y": 0,
"rows": 0,
"kind": "inserted"
}
],
"inserted_rows": 0,
"deleted_rows": 0,
"residual_percentage": 0.1,
"raw_diff_percentage": 0.1
},
"is_quarantined": true,
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"run_id": "dded282c-8ebd-44cf-8ba5-9a234973d1ec",
"identifier": "string",
"result": "string",
"classification_reason": "string",
"diff_percentage": 0,
"diff_pixel_count": 0,
"review_state": "string",
"reviewed_at": "2019-08-24T14:15:22Z",
"approved_hash": "string",
"tolerated_hash_id": "7019d9c2-0d1d-41e9-a8a2-90206607b139",
"metadata": {},
"ssim_score": 0,
"change_kind": "string",
"size_mismatch": true
}

List all visual review runs tolerated hashes

Also available via the PostHog MCP server:

  • visual-review-runs-tolerated-hashes-list — List tolerated hashes

List known tolerated hashes for a snapshot identifier.

Required API key scopes

visual_review:read

Path parameters

  • id
    string

Query parameters

  • identifier
    string
  • limit
    integer
  • offset
    integer

Response


Example request

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

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": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"alternate_hash": "string",
"baseline_hash": "string",
"reason": "string",
"diff_percentage": 0,
"created_at": "2019-08-24T14:15:22Z",
"source_run_id": "51116a97-0041-4601-85fc-eb599c2885fb"
}
]
}

Retrieve visual review runs counts

Also available via the PostHog MCP server:

  • visual-review-runs-counts-retrieve — Visual review run counts

Review state counts for the runs list.

Required API key scopes

visual_review:read

Response


Example request

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

Example response

Status 200
RESPONSE
{
"needs_review": 0,
"clean": 0,
"processing": 0,
"stale": 0
}