Playwright screenshots. A shared place to review them.
Keep browser execution in your own tests. Upload the resulting PNGs to Difora for baseline comparison, team discussions and explicit approval before merging.
When to add hosted review
Use this workflow when developers and reviewers need the same baseline, current image and diff in a browser. Keep Playwright’s own assertions for behavior. If committed image expectations and your existing pull-request process already meet your needs, an additional hosted review service may be unnecessary.
Difora does not run your browser. Your team chooses the browser version, fonts, viewport, data and CI region. Pin those inputs across the first baseline and later runs.
Capture one page
In your application repository, use Node 20+ and a running local app. Install the client and Playwright, then commit the package files. If Playwright is already installed, reuse its exact version and matching browsers.
npm install --save-dev difora playwright
npx playwright install chromium
Save as capture.mjs. Adapt the URL and readiness check to
your app; the example waits for a visible main element
and fonts. Also wait for your application data and images before
capture.
import { chromium } from 'playwright';
import { diforaScreenshot } from 'difora/playwright';
if (!process.env.TARGET_URL) throw new Error('Set TARGET_URL to your running app');
const browser = await chromium.launch();
try {
const page = await browser.newPage({
viewport: { width: 1280, height: 800 },
locale: 'en-GB', timezoneId: 'Europe/Vienna',
});
await page.goto(process.env.TARGET_URL);
await page.locator('main').waitFor();
await page.evaluate(() => document.fonts.ready);
await diforaScreenshot(page, 'home', {
fullPage: true, viewportSuffix: true, captureMetadata: true,
});
} finally {
await browser.close();
}
Start your app using its usual command. Clear only the generated
screenshots/ directory, then run the capture. Replace
port 3000 with your app’s port.
node -e "require('node:fs').rmSync('screenshots', { recursive: true, force: true })"
TARGET_URL=http://127.0.0.1:3000 node capture.mjs
Expected output: screenshots/home@1280.png and its
.png.difora.json sidecar. Keep both together. Add the
generated directory to .gitignore. Browser and theme
variants need distinct names; viewport width alone does not
distinguish them.
Upload, approve, then run again
Create your Free organization and project, let the owner accept
Agreements, and store a project upload token as the CI secret
DIFORA_TOKEN. Upload only after the complete capture
succeeds:
npx difora upload ./screenshots
The first build needs review (exit 1). Open its link, inspect each image and approve the baseline. Repeat from a clean directory in the same environment: unchanged images pass (exit 0). Usage or upload errors use exit 2; a comparison error uses exit 1, and waiting for a comparison can time out with exit 3. Keep the exit code in your pipeline; CI recipes explain branch detection and optional repository statuses.
Avoid accidental baseline changes
A build represents the complete intended snapshot set. A missing previously approved name can become a removal; a filtered test run is not a safe subset build. Keep names stable and upload PNGs only after the whole suite succeeds. See stability diagnostics and capture environments before relaxing thresholds.
Already using component stories? See Storybook visual testing.
Reference: Playwright screenshot API. Capture example uses Difora’s public client; no hosted rendering or automatic approval is implied.
Difora is an independent service. Product names identify the tools discussed; no affiliation or endorsement is implied.