How to screenshot product pages with out-of-stock and back-in-stock states
Set up repeatable out-of-stock and in-stock product states in a Shopify test store, then capture and compare them with Playwright or ScreenshotNeo.
To capture both unavailable and available product states, control the test store’s inventory and selected variant, capture the page in the same browser environment, then change only the inventory state and repeat. In Shopify, availability can depend on the selected variant and location, so record those choices along with the viewport and screenshot scope.
This guide uses a Shopify theme test store and Playwright for local captures. The same setup also works for visual regression baselines. A back-in-stock notification form is theme- or app-specific; Shopify’s inventory and theme examples do not establish one universal form or setup.
1. Set up controlled inventory in a test store
Use a development or test store rather than changing live inventory just to make screenshots. Create or choose a product with variants, such as sizes or colors, and set deliberate quantities for the variants you need to show.
- Choose a product and note the exact variant option values you plan to capture.
- Set the target variant to zero available quantity for the unavailable state. Keep another variant available if you also need to test the selector’s behavior.
- Set the target variant to a positive quantity for the available state.
- If the store has multiple locations, check the inventory for the location or market relevant to the storefront. Shopify’s test-theme guidance notes that CSV-imported inventory quantities default to zero in a multi-location test environment, so adjust them manually.
- Save the product and verify the storefront after each change.
Shopify’s test-theme examples cover variants that are available at some locations and sold out at others, as well as a variant sold out everywhere. Consequently, a product-wide assumption may be misleading: make the selection and location context explicit in the capture notes.
2. Verify the page’s rendered availability state
Before taking a screenshot, select the intended variant on the storefront and confirm the page displays the expected stock label and purchase controls. Shopify’s section-rendering example derives “In stock” or “Out of stock” from the selected variant, or the first available variant, and refreshes section content when option selections change.
If the label or button does not update, inspect the theme or app behavior before capturing. The inventory state may be correct while the page is still showing a previous selection, a cached section, or a theme-specific message. For a back-in-stock signup, check the specific theme or app documentation and verify its form independently; do not assume every store has the same feature.
3. Capture the states with Playwright
Playwright can capture a full page or a specific component, and its visual comparison feature can compare screenshots with reference images. The following runnable Node.js example captures the product detail page once for each state. Set inventory and confirm the page state before running each capture.
import { chromium } from 'playwright';
const productUrl = process.env.PRODUCT_URL;
if (!productUrl) throw new Error('Set PRODUCT_URL to the test product URL');
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({
viewport: { width: 1440, height: 1000 },
deviceScaleFactor: 1,
});
await page.goto(productUrl, { waitUntil: 'networkidle' });
await page.screenshot({ path: 'product-out-of-stock.png', fullPage: true });
await browser.close();
Run this after setting the selected variant’s quantity to zero, then repeat after changing only that quantity to a positive value and save to a distinct path such as product-in-stock.png. If the theme requires a variant selection, automate the relevant option controls before the screenshot. The selectors differ by theme, so inspect the rendered page and replace this illustrative step with the actual option selector:
// Example only: use the option selector and value from your theme.
await page.locator('select[name="Size"]').selectOption('Large');
await page.waitForLoadState('networkidle');
For a component-only capture, wait for the product information panel and screenshot that locator instead of the entire page:
const productPanel = page.locator('[data-product-information]');
await productPanel.waitFor({ state: 'visible' });
await productPanel.screenshot({ path: 'product-panel.png' });
Replace [data-product-information] with a selector that exists in your theme. A stable product panel makes a focused comparison easier to review, while a full-page capture records the surrounding page layout too.
4. Keep the comparison repeatable
- Keep the product, variant, location or market, browser version, operating environment, viewport, device scale factor, and screenshot scope the same.
- Change only the availability condition between captures.
- Wait until variant updates and relevant images have rendered before capturing.
- Control dynamic content, such as rotating promotions or timestamps, with Playwright screenshot styles or masks where appropriate.
- Generate and compare baselines in the same environment. Playwright documents that rendering can vary with the operating system, browser version, settings, hardware, power source, and headless mode.
For a visual regression test, retain the two intended state screenshots as separate references. Do not compare an out-of-stock capture against an in-stock baseline and interpret the expected button or label change as incidental layout drift.
5. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request captures a URL as an image or PDF; its API documentation describes the available parameters. Set the product to the state you want first, then capture the same URL for each state.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://your-test-store.example/products/example -o product-state.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://your-test-store.example/products/example"},
timeout=90,
)
r.raise_for_status()
open("product-state.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://your-test-store.example/products/example',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const bytes = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('product-state.webp', bytes));
Replace the example URL with a storefront URL that ScreenshotNeo can access. Cookie banners, newsletter popups, and chat widgets are removed before capture; each cleanup step can be disabled. Bot checks, blank pages, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. An MCP server lets AI agents use screenshot tools, including take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.
Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| The page says “In stock” when the test should be sold out | A different variant is selected, or that variant has quantity at another location. | Confirm the selected option and location inventory in the test store, then reload the storefront. |
| The page says “Out of stock” after increasing quantity | The storefront has not refreshed, the wrong variant was changed, or a location still has zero inventory. | Verify the exact variant and location, reload, and select the intended option again. |
| The label changes but the button does not | Theme or app logic may update separate page sections or use custom availability rules. | Inspect the theme’s variant-change handling and confirm the intended purchase control after selection. |
| Playwright times out waiting for network idle | Analytics, chat, or other connections may remain active. | Wait for a specific product selector or use a deliberate short delay after the variant update instead of relying on network idle. |
| Captures differ beyond the stock message | Browser environment, viewport, dynamic content, or selected options changed. | Match the environment and viewport and mask or stabilize the changing content. |
| A back-in-stock form is missing | The notification feature may depend on the store’s theme or an installed app. | Check that store’s theme or app documentation and configuration; it is not a universal inventory feature. |
Performance, reliability, and cost notes
For local Playwright captures, page load and rendering dominate elapsed time. Waiting for the exact product panel or a known variant update can avoid an unnecessarily broad wait, but capture only after the visible state is correct. Reuse a browser process for batches of captures and keep the viewport and environment fixed for comparable output.
For ScreenshotNeo, one request captures each URL; repeated captures of the same URL can use its configurable cache, so account for caching when inventory changes and a fresh state is required. The service offers async jobs with signed webhooks for longer workflows and bulk capture for up to 100 URLs per call. Only clean shots are billed; a response identifies the page verdict and billing status. Pricing is Free for 1,000 shots per month, Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; annual billing gives two months free. Every feature is available on every plan. Review the docs for cache controls and request options before building a capture pipeline.
FAQ
Can I show a back-in-stock notification in the screenshot?
Yes, if the store’s theme or app provides and renders that form. Its setup varies, so confirm the specific implementation and capture the state after it appears.
Should I change the product or variant between the two screenshots?
No. Keep the same product and variant for a direct availability comparison; vary the inventory state and preserve the other capture conditions.
Can a product be in stock at one location and unavailable at another?
Yes. Inventory and availability can vary across locations, so record the location or market context that the storefront uses.
Which screenshot scope should I choose?
Use a full-page capture when page layout matters. Capture the product panel when the stock message and purchase controls are the subject of the comparison.


