Placeholder Images in Storybook, Playwright, and Visual Regression Tests
A testing workflow guide for deterministic placeholder image URLs in Storybook stories, Playwright screenshots, visual regression tests, fixtures, and CI.
Visual tests are only useful when screenshots change because the UI changed, not because image fixtures, random photos, or remote media changed.
Deterministic placeholder image URLs give Storybook, Playwright, and visual regression tests stable image surfaces for cards, avatars, product grids, docs, and fallback states.
Search intent
Why test placeholder images should be deterministic
Storybook stories and visual regression tests often need image content before real assets exist. The problem is not filling the box. The problem is filling it the same way every time the test runs.
A random photo, expired CDN image, or fixture that changes between runs can create screenshot noise. A deterministic placeholder URL keeps the visual fixture stable so diffs point to real UI changes.
Stable screenshots
The same placeholder renders across local runs, CI, branches, and baseline updates.
Layout coverage
Cards, avatars, grids, banners, and media slots still exercise real dimensions and aspect ratios.
Readable state
Labels such as Product Image, User, Article Image, or Preview explain what the slot represents.
Storybook
Use placeholder URLs in Storybook args
Storybook stories should use stable data. Put deterministic placeholder URLs in args, fixtures, or mock data instead of relying on remote production images.
Use dimensions that match the component. A product card story should use a square placeholder if the real product media is square. A blog card should use a 1200x630 placeholder if the component expects an OG-style image.
export const ProductCardStory = {
args: {
title: 'Everyday Backpack',
imageUrl: 'https://fallback.pics/api/v1/800x800/F4F4F5/18181B?text=Product+Image',
},
};
export const ArticleCardStory = {
args: {
title: 'Release notes',
imageUrl: 'https://fallback.pics/api/v1/1200x630/F4F4F5/18181B?text=Article+Image',
},
}; Fixtures
Standardize image fixtures by surface
Test data gets easier to maintain when each image surface has a standard placeholder URL. Use one product image URL, one avatar URL, one article image URL, and one dashboard preview URL instead of inventing new labels per test.
This reduces screenshot churn and helps reviewers understand what a placeholder means at a glance.
export const imageFixtures = {
product: 'https://fallback.pics/api/v1/800x800/F4F4F5/18181B?text=Product+Image',
avatar: 'https://fallback.pics/api/v1/avatar/96?text=User',
article: 'https://fallback.pics/api/v1/1200x630/F4F4F5/18181B?text=Article+Image',
dashboard: 'https://fallback.pics/api/v1/600x400/F4F4F5/18181B?text=Preview',
}; Playwright
Use deterministic placeholders before taking screenshots
Playwright visual comparisons create or compare screenshots. If image content varies, tests can fail even when layout and component behavior are correct.
Use stable fixture data before calling toHaveScreenshot. For pages that load image URLs from APIs, mock the API response so the browser receives deterministic placeholder URLs.
import { test, expect } from '@playwright/test';
test('product grid visual state', async ({ page }) => {
await page.route('**/api/products', async route => {
await route.fulfill({
json: [
{
name: 'Everyday Backpack',
imageUrl: 'https://fallback.pics/api/v1/800x800/F4F4F5/18181B?text=Product+Image',
},
],
});
});
await page.goto('/products');
await expect(page).toHaveScreenshot('product-grid.png');
}); Network mocking
Mock image requests when the app cannot change fixture URLs
Sometimes a page under test still points to production image URLs. If you cannot change the fixture data, intercept image requests in Playwright and fulfill them with a deterministic SVG body.
This is useful for visual tests where layout matters but the real image content does not.
const svgBody =
'<svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" viewBox="0 0 800 800">' +
'<rect width="100%" height="100%" fill="#F4F4F5"/>' +
'<text x="50%" y="50%" fill="#18181B" font-size="64" text-anchor="middle" dominant-baseline="middle">Product Image</text>' +
'</svg>';
await page.route('**/*', async route => {
if (route.request().resourceType() === 'image') {
await route.fulfill({
status: 200,
contentType: 'image/svg+xml',
body: svgBody,
});
return;
}
await route.continue();
}); Visual regression
Reduce screenshot noise before tuning thresholds
Do not start by raising visual diff thresholds. First remove avoidable sources of noise: random images, timestamps, animations, inconsistent fonts, live remote media, ads, and user-specific data.
Deterministic placeholder URLs help with one of the most common noise sources: image content that should not be part of the assertion.
Control inputs
Mock API data, image URLs, dates, locale, theme, and feature flags before taking screenshots.
Freeze media
Use deterministic placeholders for image slots that are not the subject of the test.
Assert the right thing
Use visual snapshots for layout and appearance, not unpredictable remote content.
States
Test loading, missing, and failed-image states separately
A component can look correct with a normal image and still break when the image is missing or fails to load. Add separate stories or tests for each state.
Use skeleton placeholders for loading states, static labeled placeholders for known missing media, and failed-load tests to verify fallback behavior.
export const Loading = {
args: {
imageUrl: 'https://fallback.pics/api/v1/skeleton/800x800',
},
};
export const MissingImage = {
args: {
imageUrl: 'https://fallback.pics/api/v1/800x800/F4F4F5/18181B?text=Product+Image',
},
};
export const FailedImage = {
args: {
imageUrl: '/broken-product-image.jpg',
fallbackUrl: 'https://fallback.pics/api/v1/800x800/F4F4F5/18181B?text=Product+Image',
},
}; CI
Keep CI baselines portable
Visual tests can still vary by operating system, browser version, fonts, antialiasing, and viewport. Deterministic image placeholders do not solve every visual testing problem, but they remove one major source of variance.
Run screenshot tests in a consistent environment and commit baseline updates intentionally. The placeholder URL should not change unless the visual state being tested changes.
Privacy
Keep test placeholder URLs free of private data
Test artifacts are often shared widely: CI logs, HTML reports, trace files, screenshots, pull requests, and bug reports. Treat placeholder URLs in tests as public.
Do not put secrets, tokens, email addresses, customer names, account IDs, order IDs, private product names, regulated data, or internal identifiers in placeholder URL text.
// Good test labels
https://fallback.pics/api/v1/800x800?text=Product+Image
https://fallback.pics/api/v1/avatar/96?text=User
https://fallback.pics/api/v1/1200x630?text=Article+Image
// Keep private values out of URL text Internal links
Where to go next
Use the placeholder image API guide for URL syntax, then use the layout shift and framework guides to make image states production-safe.
Use the skeleton guide when deciding whether a visual state should represent loading, missing media, or a failed image.
Placeholder image API: https://fallback.pics/placeholder-image-api/
Skeleton placeholder guide: https://fallback.pics/blog/skeleton-placeholder-images-vs-static-fallbacks/
Prevent image layout shift: https://fallback.pics/blog/prevent-layout-shift-missing-images/
React image fallback: https://fallback.pics/guides/react-image-fallback/
Next.js image fallback: https://fallback.pics/guides/nextjs-image-fallback/
SVG placeholder images: https://fallback.pics/blog/svg-placeholder-images-fast-cacheable-scalable/
Cache-Control guide: https://fallback.pics/blog/cache-control-placeholder-images-cdn-browser/ Key takeaways
What to standardize before shipping
- Use deterministic placeholder URLs in Storybook stories, fixtures, and screenshot tests.
- Mock API responses or image requests in Playwright when live media would make screenshots noisy.
- Standardize placeholder URLs by surface: product, avatar, article, dashboard, skeleton, and missing media.
- Test normal, loading, missing, and failed-image states separately.
- Keep placeholder URL labels generic because screenshots, traces, and CI reports are often shared.
Production fallback layer
Use fallback.pics anywhere an image URL is accepted.
Start with one deterministic URL and standardize fallback behavior across your design system.