The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →To test pages that require authentication with BackstopJS, give its browser a valid, reproducible session, wait for the authenticated view to finish rendering, and compare the new capture with an approved reference. BackstopJS documents three ways to provide browser state: import cookies with cookiePath, prepare state with a custom onBeforeScript, or use the Playwright engine’s engineOptions.storageState for cookies and local storage. These are alternatives, not interchangeable fixes for every login flow. BackstopJS’s repository documentation describes the configuration options; check the README matching your installed version if a setting differs.
Understand the BackstopJS visual-test cycle
BackstopJS captures a reference image, captures the page again during a test, then reports visual differences. For authenticated pages, the browser state must be valid for both captures, and both captures must reach the same intended application view.
- Set up the scenario and authenticate its browser context.
- Run
backstop referenceto create the baseline image for the state you intend to accept. - Run
backstop testto capture and compare the current page against that reference. - Inspect the reported differences. Run
backstop approveonly when you have reviewed the changes and want to replace the reference.
BackstopJS documents using its CLI in a build process or before deployment. Its test command returns a nonzero status when a layout test fails, and CI workflows can produce JUnit reports. Treat a changed screenshot as a review item, not an automatic reason to approve a new baseline.
Choose how to provide authentication state
Use the least complicated method that represents your application’s real browser session. A cookie file can be enough for a cookie-backed session; an application that relies on local storage may need Playwright storage state; a more involved application-specific setup may need a script. BackstopJS’s documented mechanisms do not guarantee that a static session will work with every identity provider, MFA flow, or token-refresh policy.
#1 Best Overall
| Method | Use it when | Important detail |
|---|---|---|
cookiePath |
A valid session can be represented by cookies in a JSON file. | The path is relative to the current working directory. BackstopJS’s default onBefore script imports the file. |
Custom onBeforeScript |
You need scenario-specific browser setup or app-specific preparation before capture. | The hook runs before each scenario and receives the browser page and scenario. Use APIs appropriate to the selected engine. |
Playwright storageState |
The saved browser state needs cookies and local storage. | Select the Playwright engine and set engineOptions.storageState to the state JSON file. |
Import cookies with cookiePath
BackstopJS’s default onBefore script can load a JSON cookie file configured on a scenario. A minimal scenario could look like this:
{
"id": "account-dashboard",
"url": "https://example.com/account",
"cookiePath": "backstop_data/engine_scripts/account-cookies.json",
"readySelector": "[data-testid="account-dashboard"]"
}
Use a cookie file created for the same application environment and domain as the scenario URL. The documented path is relative to the current working directory, so run BackstopJS from the expected project directory or adjust the path accordingly. Cookies can expire or be invalidated; a formerly working file is not proof that authentication still succeeded. Keep real cookie files and session tokens out of public examples and source control.
Rank #2
Prepare state with a custom script
Configure onBeforeScript when a cookie import alone is insufficient or when setup needs to vary by scenario. The documented hook receives the page and scenario, so a script can perform engine-appropriate preparation before the capture. BackstopJS examples show loading cookies in a Puppeteer script; do not assume that a Playwright-only API works in the Puppeteer engine.
Place script files under the directory configured by paths.engine_scripts; the project documentation recommends using a project directory for these scripts. A custom onBefore handler can receive page, scenario, viewport, isReference, Engine, and config. Consult the README for your installed version for the exact hook format and engine APIs.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesRank #3
For a full scripted login, avoid embedding credentials in an example or committing them to the repository. Use the secret-management mechanism provided by your CI or local environment, and make sure the flow is permitted and repeatable in your test environment. The documentation describes setup hooks, but does not define credential rotation or identity-provider policy.
Load Playwright storage state
When the authenticated browser state includes cookies and local storage, BackstopJS documents Playwright’s engineOptions.storageState as an option. For example, the configuration shape is:
Rank #4
{
"engine": "playwright",
"engineOptions": {
"storageState": "backstop_data/engine_scripts/auth-state.json"
},
"scenarios": [
{
"label": "Authenticated account dashboard",
"url": "https://example.com/account",
"readySelector": "[data-testid="account-dashboard"]"
}
]
}
Use a storage-state file produced for the appropriate application environment. Keep it secret: it may contain active session material. BackstopJS documents Playwright browser choices including Chromium, Firefox, and WebKit; the storage-state setting belongs to its Playwright engine configuration, not Puppeteer’s.
Make the captured page deterministic
Authentication is only one part of a reliable visual test. A successful login does not mean the view is fully rendered, and a screenshot taken during loading can create noisy or misleading differences.
- Wait for the intended view. Use
readySelectorfor a selector that appears when the target page is ready, orreadyEventwhen the application emits a specific readiness string. A fixeddelayis available, but a selector or app readiness event ties the wait more directly to the expected state. - Set an appropriate timeout.
readyTimeoutcontrols how long BackstopJS waits for readiness. If it expires, verify authentication and the selector or event before simply increasing the timeout. - Use
onReadyScriptfor final view setup. Apply it when an interaction is part of the state being tested, such as opening a particular panel. BackstopJS also supports scenario interactions such as clicks, hovers, and key presses. - Choose capture scope deliberately. A scenario can capture the full page or target CSS selectors. Selector capture uses the first match by default; use
selectorExpansionto capture all matches andexpectto assert the selected-item count when appropriate. - Control changing content. Keep the test data, account state, and dynamic page elements stable where possible. Otherwise, genuine content variation can appear as a visual regression even when the layout is unchanged.
Run authenticated visual tests in CI
Run reference and test captures in a consistent environment, and keep the authentication state available securely to the runner. BackstopJS notes that rendering can vary between environments and identifies Docker as one way to reduce that variation; it is a reproducibility aid, not a guarantee that all differences disappear.
- Provide the runner with the correct cookie or Playwright state file, or configure the required setup hook.
- Run the visual test against the intended environment and collect BackstopJS’s report and images as CI artifacts.
- Use the command’s exit status to fail the job when a layout test fails. Configure JUnit reporting if your CI system consumes that format.
- Review the visual diff before changing the reference baseline. Approve only expected changes.
Do not reuse a state file across unrelated environments without confirming its domain, validity, and intended account. BackstopJS’s documentation does not specify a universal session-refresh approach; that depends on your application and identity provider.
Troubleshooting authenticated BackstopJS captures
| Symptom | Likely cause | What to check |
|---|---|---|
| The capture shows a login page | The session is missing, expired, scoped to another environment, or not being loaded by the configured engine. | Confirm the scenario URL and cookie domain, check that the state file exists relative to the working directory, and verify the selected engine matches the setup method. |
readySelector never appears |
The page did not authenticate, the selector changed, or the app has not reached the expected view. | Inspect the captured page and browser output; confirm the selector exists on the authenticated route and increase readiness time only if the page genuinely needs longer. |
| Playwright state has no effect | storageState is configured under the wrong engine or the state does not represent the required browser context. |
Confirm "engine": "playwright", the state-file path, and that the saved state includes the authentication data the app uses. |
| Tests differ between local and CI | Browser or rendering environments, data, or page timing differ. | Align the environments where practical, stabilize test data, use explicit readiness conditions, and consider Docker as a way to reduce environment variation. |
| Only one repeated element is captured | Selector capture defaults to the first matching element. | Use selectorExpansion to capture all matches and expect when you need to assert the expected selected count. |
| Approval hides an unexpected change | A changed reference was accepted without reviewing the diff. | Restore or regenerate the intended baseline and review the report before running backstop approve. |
Or skip the browser setup
If you need a screenshot rather than a repeatable visual-regression baseline, ScreenshotNeo provides a website screenshot API and MCP server. Its API accepts one GET request with a URL and returns a PNG, JPEG, WebP, or PDF. For a basic capture:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/account -o shot.webp
See the ScreenshotNeo API documentation for authentication and request options. Cookie banners, newsletter popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots, and the free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. ScreenshotNeo is a capture service, not a replacement for BackstopJS’s reference-and-diff workflow. Sign up for ScreenshotNeo’s free plan.
Frequently Asked Questions
Can BackstopJS use a saved login session?
Yes. It can import cookies with cookiePath or load cookies and local storage through Playwright storageState, provided the saved state is valid for the application and environment.
Does BackstopJS support authenticated captures in Firefox or WebKit?
The project documentation lists Chromium, Firefox, and WebKit as browser choices for its Playwright engine. Engine-specific configuration should be checked against the README for the installed version.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




