Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Add each visual-regression case as an object in BackstopJS’s top-level scenarios array. Give it a descriptive label and a url; put settings shared by multiple cases in scenarioDefaults, then override them on individual scenarios only when needed. Use backstop test --filter to run a focused subset while you work.

Add a scenario to the configuration

BackstopJS reads scenario definitions from the top-level scenarios array. Each scenario requires a label and a url; other scenario properties are optional and should be added to control the page state or capture behavior you need. Labels also contribute to screenshot naming and are used by the CLI’s regular-expression filter.

If you have not initialized a project, the official README documents backstop init as a way to scaffold its configuration. By default, BackstopJS looks for backstop.json in the project root.

{
  "scenarios": [
    {
      "label": "Product listing",
      "url": "https://example.test/products"
    },
    {
      "label": "Product detail",
      "url": "https://example.test/products/example"
    }
  ]
}

Replace the example URLs with routes available in your test environment. Use labels that distinguish routes or states clearly, especially if you intend to filter by them.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall

Reuse settings with scenarioDefaults

Move values that should apply to many scenarios into scenarioDefaults. Common examples include a cookie file, wait behavior, or selectors. A property explicitly set on a scenario takes precedence over the matching default.

{
  "scenarioDefaults": {
    "readySelector": "main"
  },
  "scenarios": [
    {
      "label": "Product listing",
      "url": "https://example.test/products"
    },
    {
      "label": "Account page",
      "url": "https://example.test/account",
      "readySelector": "[data-test='account-ready']"
    }
  ]
}

In this illustrative configuration, the listing uses the shared main selector, while the account scenario supplies its own selector. Take care with explicit empty arrays: an empty scenario-level selectors array overrides selectors supplied through scenarioDefaults; it does not mean “inherit the defaults.”

Generate reusable scenarios from JavaScript data

For a static list, JSON is straightforward. Use a JavaScript configuration when you need comments, functions, or scenario objects generated from a route list. BackstopJS documents JavaScript configuration, including a configuration function that returns an object; pass the JavaScript config path with --config. The exact helper or folder structure is up to your project.

const routes = [
  { label: 'Product listing', path: '/products' },
  { label: 'Product detail', path: '/products/example' }
];

const scenarios = routes.map(({ label, path }) => ({
  label,
  url: `https://example.test${path}`,
  readySelector: 'main'
}));

module.exports = {
  id: 'shop',
  viewports: [{ label: 'desktop', width: 1280, height: 800 }],
  scenarios
};

This pattern uses ordinary JavaScript to build the documented configuration shape. Confirm that its fields and behavior match the BackstopJS version installed in your project; the repository README is on a moving master branch, and versions can differ.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If another Node application or task runner already constructs the configuration, the Node API can accept a config object directly. This lets you centralize route data or generate scenarios without requiring the configuration to be maintained as a static JSON list.

Run only the scenarios you are changing

Use backstop test to capture test images and compare them with the current references. Add --filter with a regular expression to select scenarios whose labels match it:

backstop test --filter="Product listing"

For example, a broader expression can match a family of related labels. Keep the expression aligned with how your team names scenarios; the filter matches labels, not URLs.

Understand reference, test, and approve

These commands serve different purposes in the visual-regression workflow:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • backstop reference captures baseline images. It uses each scenario’s url unless that scenario defines referenceUrl, in which case the reference capture uses that URL.
  • backstop test captures test images and compares them with the current references.
  • backstop approve promotes the latest test images to the reference collection.

reference creates baselines; it does not perform comparisons. Review test differences before approving them. In CI, treat a baseline update as an intentional decision rather than automatically approving every changed capture. The BackstopJS documentation describes build-process integration, and the Node API can be invoked from another Node application or task runner.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

JSON or JavaScript: choose by reuse needs

Approach Best fit Reuse method
JSON configuration A static scenario list and shared settings Use scenarioDefaults for common values.
JavaScript configuration Comments, functions, or generated scenario data Construct scenario objects from centralized route data.
Node API config object A Node program or task runner that already builds configuration Pass the constructed config object to the API.

Troubleshoot common configuration problems

  • A scenario is not usable: verify that it has both a label and a url.
  • A shared selector or other setting is not taking effect: check for a scenario-level property overriding the default. In particular, an explicit empty selectors array replaces the default array.
  • A filtered test runs no scenarios you expected: check that the regular expression in --filter matches the scenario labels, not their URLs.
  • Reference and test captures show different pages: check whether referenceUrl is configured. References use it when present; otherwise they use url.
  • A documented option behaves differently in your project: check documentation corresponding to the installed version. The repository README’s master branch can describe behavior that differs from a particular package version.

Or skip the browser setup

If your immediate need is a screenshot rather than a BackstopJS visual-regression baseline, ScreenshotNeo provides a one-call website screenshot API. It is not a replacement for BackstopJS’s reference, comparison, and approval workflow.

For example, request a PNG screenshot of a page with cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.test/products -o shot.png

See the ScreenshotNeo API documentation for request options. Cookie banners, newsletter popups, and chat widgets are removed before capture; bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Its MCP server gives AI agents tools to take screenshots, inspect page information, and capture PDFs. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Sign up for ScreenshotNeo’s free plan.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.