Schema reference
The normative description of the format is the JSON Schema (draft 2020-12) at https://visual-regression.dev/schema/v1.json, shipped in the visual-regression-manifest package as schema.json. This page is generated from it.
A machine-readable record of every screenshot comparison made during a test run, written by a visual regression tool and read by CI tooling (PR comment bots, review dashboards, approval tools). Runner-agnostic: everything specific to the test runner lives in runner. The envelope, the CI block and the open extra objects follow CTRF (ctrf.io) naming so a manifest maps onto a CTRF report without loss; see the toCtrf/fromCtrf converters. Consumers must ignore keys they do not know.
Top level
| field | type | required | description |
|---|---|---|---|
reportFormat | "visual-regression-manifest" | yes | Identifies the document as a visual regression manifest (CTRF has reportFormat: "CTRF"). |
specVersion | string | yes | Version of this format (semver). The major is bumped on breaking changes only; readers accept every version with the major they know. |
createdAt | timestamp | yes | When the run started (ISO 8601). |
updatedAt | timestamp | yes | When the file was last written (ISO 8601). Writers rewrite the file after every comparison, so a manifest is complete even when the run was aborted. |
projectRoot | string | yes | Absolute path (on the machine that ran the tests) that every relative path in the manifest resolves against. Not necessarily the repository root: ci.workspace is the checkout directory. |
platform | platform | yes | |
ci | null | ci | yes | CI metadata detected from environment variables. null outside CI, { "provider": null } when only a generic CI flag was set. |
tool | tool | yes | |
options | object | yes | Global tool options as configured, in the writer's vocabulary (for the Cypress plugin: every pluginVisualRegression* option with the prefix stripped). |
runner | runner | yes | |
upload | upload | ||
summary | summary | yes | |
entries | array of entry | yes | |
extra | extra |
timestamp
Type: string, matching ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$.
status
passed: within threshold. failed: above threshold, .actual and .diff images kept for review. missing-baseline: no baseline and the tool was told not to create one. created: no baseline, the actual image became the baseline. updated: the baseline was overwritten on request. approved: the baseline was replaced from a review UI. failed and missing-baseline are the entries that need a human. In CTRF terms missing-baseline is failed and created, updated, approved are passed, with the manifest status kept in rawStatus.
One of "passed", "failed", "missing-baseline", "created", "updated", "approved".
tool
What wrote the manifest: a visual regression plugin, a converter, a review tool. Same shape as CTRF's tool.
| field | type | required | description |
|---|---|---|---|
name | string | yes | |
version | string | ||
extra | extra |
summary
Counts over entries, so a consumer can tell whether a human is needed without reading them all. Writers recompute it on every write; readers merging several manifests recompute it from the merged entries.
| field | type | required | description |
|---|---|---|---|
entries | integer | yes | |
passed | integer | yes | |
failed | integer | yes | |
missingBaseline | integer | yes | |
created | integer | yes | |
updated | integer | yes | |
approved | integer | yes | |
needsHuman | integer | yes | failed + missingBaseline. |
platform
The machine that ran the tests (the host), which is not necessarily the device under test: for a mobile or remote-device run see the entries' target. Named like CTRF's environment: osPlatform is an open string (Node-based writers use process.platform names: linux, darwin, win32), osRelease the kernel release, osVersion the human-readable OS version.
| field | type | required | description |
|---|---|---|---|
osPlatform | string | yes | |
arch | string | yes | |
osRelease | string | ||
osVersion | string |
browser
| field | type | required | description |
|---|---|---|---|
name | string | yes | |
version | string | ||
family | string | ||
headless | boolean |
target
What was captured, for tools that are not a browser: a desktop or mobile application on a device, an emulator or a remote farm. Everything is optional; unknown keys are allowed.
| field | type | required | description |
|---|---|---|---|
kind | string | Known values: browser, desktop, mobile, embedded; free-form otherwise. | |
os | string | ||
osVersion | string | ||
arch | string | ||
device | object | ||
display | object | ||
locale | string | ||
theme | string | ||
app | object | ||
driver | string | ||
emulated | boolean |
device
| field | type | required | description |
|---|---|---|---|
model | string | ||
id | string | ||
formFactor | string |
display
| field | type | required | description |
|---|---|---|---|
width | number | ||
height | number | ||
density | number | Device pixels per logical pixel (scale factor / dpr). | |
orientation | string |
app
| field | type | required | description |
|---|---|---|---|
id | string | ||
version | string | ||
build | string |
viewport
| field | type | required | description |
|---|---|---|---|
width | number | yes | |
height | number | yes |
ci
Where the run happened. Keys that have a CTRF environment equivalent carry its name (commit, branchName, repositoryName, repositoryUrl, buildId, buildName, buildNumber, buildUrl); the rest is what CTRF lacks.
| field | type | required | description |
|---|---|---|---|
provider | string | null | yes | Known values: github, gitlab. Other CI systems are free-form lowercase ids; null when only a generic CI flag was set. |
repositoryName | string | owner/repo (GitHub) or group/project (GitLab). | |
repositoryUrl | string | ||
commit | string | On GitHub pull_request events this is the synthetic merge commit; tools that write to the PR branch must use pullRequest.headSha. | |
ref | string | ||
branchName | string | ||
pullRequest | null | object | ||
event | string | ||
buildId | string | The run or pipeline id (GitHub GITHUB_RUN_ID, GitLab CI_PIPELINE_ID); locates the artifacts together with runAttempt. | |
buildName | string | The workflow or pipeline name. | |
buildNumber | string | ||
buildUrl | string | Link to the run or job page. | |
runAttempt | string | ||
job | string | ||
jobId | string | ||
serverUrl | string | ||
workspace | string | Absolute path of the checked-out repository on the CI machine. |
runner
What ran the tests (Cypress, Playwright, a mobile driver), as opposed to tool, which wrote the manifest. Only name is required; the remaining keys are runner vocabulary and writers may add their own.
| field | type | required | description |
|---|---|---|---|
name | string | yes | |
version | string | ||
testingType | string | ||
mode | "run" | "open" | ||
configFile | string | Relative to projectRoot, / separators. | |
browser | browser | ||
specs | array of string | Test files of the run relative to projectRoot, when known up front. | |
specPattern | string | array of string | ||
baseUrl | string | null | ||
viewport | viewport | ||
cloud | object | Hosted runner dashboard details, when recording. |
cloud
Hosted runner dashboard details, when recording.
| field | type | required | description |
|---|---|---|---|
runUrl | string | ||
group | string | ||
tag | string | ||
parallel | boolean |
upload
Where the images and snapshots of the run were uploaded to, when an upload service was used.
| field | type | required | description |
|---|---|---|---|
buildId | string | yes | |
url | string | yes | |
level | "images" | "images+snapshot" | yes |
image
| field | type | required | description |
|---|---|---|---|
path | string | null | yes | Relative to projectRoot, / separators; null when the file does not exist. Baseline, actual and diff of an entry share one extension (PNG for all current writers); .actual and .diff go before it. |
width | integer | ||
height | integer | ||
extra | extra |
attachment
Any other file an entry wants to point at (a trace, a video, a DOM snapshot). Same shape as a CTRF attachment; path is relative to projectRoot.
| field | type | required | description |
|---|---|---|---|
name | string | yes | |
contentType | string | yes | |
path | string | yes | |
attachmentId | string | ||
extra | extra |
subject
What the screenshot is a picture of, as opposed to the test that took it: a component story, a page, a screen. Tool-neutral; the id is whatever the producer uses to name the thing (for example a Storybook story id), so tools can group or match entries by it.
| field | type | required | description |
|---|---|---|---|
id | string | yes | |
kind | string | Known values: story, page, component, screen; free-form otherwise. |
extra
Open metadata keyed by namespace, like CTRF's extra; every value is an object. Consumers must ignore namespaces they do not know. Conventional namespaces on an entry or image: design (a design software source: tool, file, node, version, for example the Figma file, frame and version a baseline was exported from) and storybook (args, globals). visualRegression is reserved for the CTRF converters. Nothing here takes part in baseline identity.
Type: object.
renderer
Where the pixels came from, as opposed to platform, which is where the test ran. Entries with different renderers are different baselines.
| field | type | required | description |
|---|---|---|---|
backend | string | yes | Known values: native (the test runner's own capture), docker, cloud. Writers may add their own, e.g. device or emulator. |
name | string | What rendered the pixels: a browser, an app or a device. Absent when backend says enough. | |
version | string | ||
browser | string | Browser name; kept for browser renderers, same as name. | |
browserVersion | string | ||
rendererVersion | string | Version of the renderer image; absent under native. | |
imageDigest | string | Content digest of the renderer image; absent under native. | |
fallback | boolean | true when an auto renderer degraded to native. |
sha256
Type: string, matching ^[0-9a-f]{64}$.
entryOptions
The comparison options the entry was made with, exactly as configured (imagesPath keeps its tokens unexpanded).
| field | type | required | description |
|---|---|---|---|
imagesPath | string | yes | |
title | string | ||
maxDiffThreshold | number | yes | |
diffConfig | object | yes | |
createMissingImages | boolean | yes | |
updateImages | boolean | "failures-only" | yes | |
forceDeviceScaleFactor | boolean | Browser runners only. | |
matchAgainstPath | string | ||
screenshotConfig | object | Capture options in the runner's vocabulary (Cypress screenshot config); JSON-serialisable keys only. |
entry
One screenshot comparison. Maps onto a CTRF test of type: "visual": name is the test name, test.titlePath without its last element the suite, test.filePath the file path, message the message, duration the duration.
| field | type | required | description |
|---|---|---|---|
name | string | yes | Screenshot name, equal to the baseline file stem. Unique within a run. |
test | object | yes | |
status | status | yes | |
comparison | object | yes | |
images | object | yes | |
attachments | array of attachment | ||
baselineWritten | boolean | yes | true whenever the baseline file was (re)written during the run, whatever the status. |
recordedAt | timestamp | yes | |
duration | integer | How long the capture and comparison took, in milliseconds, when the writer measured it. | |
platform | object | Where this screenshot was taken; per entry because manifests of several machines get merged. | |
target | target | ||
subject | subject | ||
extra | extra | ||
variant | string | Producer-chosen id that tells entries of the same screenshot name apart (device, OS version, density, locale, theme, project, ...). Part of the baseline identity when merging manifests; absent, identity falls back to platform.osPlatform + platform.browser.name + renderer. | |
viewport | viewport | ||
options | entryOptions | ||
renderer | renderer | ||
hashes | object | sha256 of the files listed in images; a key is present only when the file exists. | |
message | string | yes | Human-readable summary, informational only. |
test
| field | type | required | description |
|---|---|---|---|
filePath | string | yes | Test file relative to projectRoot, / separators. Empty when unknown. |
titlePath | array of string | yes | Describe blocks and test title, outermost first. |
retry | integer | yes | Attempt index of the test this comparison belongs to: 0 for the first attempt (CTRF's retries is a count, not an index). |
comparison
| field | type | required | description |
|---|---|---|---|
diffRatio | number | yes | Share of differing pixels, 0..1. 0 when no comparison ran. |
threshold | number | yes |
images
| field | type | required | description |
|---|---|---|---|
baseline | image & any | yes | The baseline path is always known, even when the file does not exist yet (missing-baseline). |
actual | image | yes | |
diff | object | yes |
diff
| field | type | required | description |
|---|---|---|---|
path | string | null | yes |
platform
Where this screenshot was taken; per entry because manifests of several machines get merged.
| field | type | required | description |
|---|---|---|---|
osPlatform | string | yes | |
osRelease | string | ||
osVersion | string | ||
arch | string | ||
browser | browser | Absent for non-browser targets (desktop and mobile apps). |
hashes
sha256 of the files listed in images; a key is present only when the file exists.