How to Ignore Dynamic Content in BackstopJS Screenshots
Use BackstopJS selectors to hide or remove volatile elements, or replace live content with deterministic fixtures for reliable visual regression tests.
Use BackstopJS hideSelectors when dynamic content should disappear from the screenshot but keep its space in the layout. Use removeSelectors when the element and its footprint should be removed. For the most reliable visual regression coverage, replace live dynamic data with deterministic fixtures when you can. [BackstopJS documentation]
1. Choose what the test should preserve
Before changing configuration, decide whether the element’s dimensions and position are part of what the scenario should test.
| Approach | What happens | Use it when | Watch for |
|---|---|---|---|
hideSelectors |
BackstopJS sets matched elements to visibility: hidden; the element remains in layout flow. |
The region’s geometry should remain covered, but its changing pixels should not cause diffs. Examples include a stable ad slot or timestamp. | Its reserved space remains, and other visible parts of the component can still differ. |
removeSelectors |
BackstopJS removes matching elements before the screenshot. | The content has unpredictable size and should not appear in the capture. | Removing an element can change downstream positioning. Verify that the resulting reflow is acceptable for the scenario. |
| Deterministic data | The application renders controlled fixture data instead of changing live content. | You want to test layout behavior caused by content while keeping the input reproducible. | Consider representative content lengths if they affect layout. |
BackstopJS recommends known static data stubs for dynamic applications. This can keep the test reproducible while still letting you check how different content lengths affect the page. [BackstopJS documentation]
2. Hide dynamic content and keep its layout space
Add hideSelectors to the relevant scenario. The selector below is illustrative: replace it with one that matches the page under test.
{
"scenarios": [
{
"label": "page with a dynamic ad",
"url": "https://example.test/page",
"hideSelectors": ["#dynamic-ad"]
}
]
}
This hides the matched element’s pixels while retaining its layout footprint. Use this for content such as rotating text or an ad whose reserved dimensions should remain part of the visual check. [BackstopJS documentation]
3. Remove dynamic content and its footprint
Use removeSelectors if an unpredictable region should be absent entirely from the captured page:
{
"scenarios": [
{
"label": "page without unpredictable feed",
"url": "https://example.test/page",
"removeSelectors": ["#dynamic-feed"]
}
]
}
Removing a variable-height feed may shift everything below it. That can be useful if the feed is outside the scope of the scenario, but it can also hide or create layout differences that matter. Compare the resulting screenshot with the intended page behavior before keeping the rule.
4. Put the rule at the right scope
Selector arrays can be set on a scenario or in shared configuration, depending on the configuration structure and whether the rule should apply to one scenario or several. Use scenario-level rules for page-specific volatility. Use shared configuration only when the same selector behavior is appropriate across the scenarios that inherit it. Confirm the supported placement in the documentation for your installed BackstopJS version. [BackstopJS documentation]
5. Keep content deterministic when possible
Selectors suppress content from a particular visual check; they do not make the underlying live data stable. If you need to verify component rendering, use a fixed API response, fixture, or other controlled application state. For pages where content length affects layout, use fixtures of representative lengths so the test can catch wrapping, overflow, and spacing regressions without depending on changing production data.
For custom application setup, BackstopJS provides onReadyScript, which can perform setup or simulate a state before capture. Use it to establish a deterministic state when the application supports that approach. [BackstopJS documentation]
6. Do not use waits to hide volatility
Readiness settings control when capture happens; they do not make changing content reproducible:
readySelectorwaits for a selector to appear.readyEventwaits for the application to log a specified console message.delaywaits for a fixed duration. When combined withreadyEvent, the delay applies after that event.
Use these settings to capture the intended application state. If a clock, rotating promotion, or live feed keeps changing after readiness, control the data or hide/remove the appropriate region instead. [BackstopJS documentation]
7. Validate the resulting scenario
- Run the scenario and inspect the captured screenshot as well as the visual diff.
- Check that each selector matches the intended element on the pages where the rule applies.
- Confirm that hiding preserves the geometry you want to test.
- Confirm that removing the element does not create unwanted reflow or conceal an important layout regression.
- Check neighboring elements, borders, shadows, and other changing pixels. Adjust the selector scope if the volatile area is larger or smaller than expected.
- Keep an appropriate deterministic fixture for any behavior the selector rule has taken out of coverage.
BackstopJS also documents misMatchThreshold and requireSameDimensions as comparison settings. They tune diff tolerance and dimension checks; they do not stabilize live content. The repository page consulted for this guide reports defaults of 0.1 and true respectively, but defaults can depend on the installed version and configuration. Check the documentation bundled with your version before relying on them. [BackstopJS documentation]
8. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| The dynamic area still appears in the screenshot. | The selector does not match the rendered element, or it targets a different element than expected. | Inspect the rendered page and refine the selector. Confirm the selector is configured for the scenario that is being captured. |
| A blank gap remains where content was hidden. | hideSelectors preserves layout flow. |
This is expected when the goal is to keep geometry stable. If the footprint should disappear, use removeSelectors and review the resulting layout. |
| Content below the removed region shifts. | Removing an element changes the page’s layout. | Use hideSelectors if the element’s space should remain, or use deterministic content if its layout behavior matters. |
| The diff still changes around a hidden component. | The selector may cover only the changing child, while a border, shadow, sibling, or surrounding region remains dynamic. | Inspect the diff and target the smallest appropriate region that excludes the volatility without removing behavior the scenario should protect. |
| The screenshot captures a loading or intermediate state. | The page was captured before the intended state was ready. | Use readySelector or readyEvent where appropriate, then add delay only if a fixed settling period is needed. These control timing, not content stability. |
| The test passes despite a meaningful visual change. | A selector or a permissive mismatch threshold may have removed too much coverage. | Review the baseline, the changed screenshot, selector scope, and comparison settings. Restore deterministic content or narrow the ignored area. |
9. Performance, reliability, and cost considerations
Ignoring a region reduces noise from that region, but it also reduces what the scenario verifies. Keep the ignored area no broader than necessary, and use controlled fixtures when the content or its geometry is part of the behavior under test. Readiness waits can help the capture reach the intended state, but long delays alone do not make a live page repeatable. For exact comparison behavior and defaults, use the documentation for the BackstopJS version installed in the project. [BackstopJS documentation]
10. Or skip the browser setup
If you need a screenshot endpoint instead of maintaining capture-browser setup, ScreenshotNeo takes a screenshot from one GET request. It accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
See the ScreenshotNeo API documentation for request options. This cURL example saves a WebP screenshot:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.test/page -o shot.webp
Python:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.test/page"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.test/page'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
ScreenshotNeo includes full-page capture, CSS selector capture, viewport and device options, custom CSS and JavaScript, readiness waits, cookies and headers, caching, asynchronous jobs, bulk capture, and PDF options. It offers 1,000 screenshots a month free with no card; paid plans start at $5 for 3,000 screenshots. Sign up for free and try ScreenshotNeo.
FAQ
Does hiding an element preserve its space?
Yes. hideSelectors uses visibility: hidden, so the matched element remains in layout flow. [BackstopJS documentation]
Should I ignore a changing element or stub its data?
Stub the data when the rendered content or its effect on layout is behavior you want to test. Ignore it when that live value is outside the scenario’s purpose.
Can a longer delay stop dynamic content from changing?
No. A delay changes capture timing only. Use controlled data or a selector rule to address volatility.
Will changing the mismatch threshold fix flaky screenshots?
It can change how much difference is tolerated, but it does not make the page deterministic. First address the source of volatility and confirm the scenario still covers the behavior you care about.


