How to Use BackstopJS for Screenshot Testing on an Indian WordPress Site
Set up BackstopJS to compare WordPress pages across changes, stabilize dynamic content, and review visual differences across browsers and environments.
BackstopJS takes browser screenshots of configured pages and compares them with approved reference images. For a WordPress site, install it in the project that runs your tests, point scenarios at a reachable local or staging site, create baselines with backstop reference, and run backstop test after changes. Inspect the report before using backstop approve, because approval replaces the images used as future baselines.
BackstopJS is a general web application visual testing tool. The reviewed documentation does not describe a WordPress plugin or India-specific setup. The examples below apply its general workflow to WordPress pages; choose URLs and states that reflect your own site, and verify its localization, fonts, scripts, and hosting behavior in the test environment. See the BackstopJS project documentation for version-specific details.
1. Install BackstopJS and choose where it runs
For a project-local setup, install BackstopJS with npm and use its CLI from the project. This keeps the test dependency with the code being tested. Pin the version in your project lockfile so teammates and CI use the same dependency version.
npm install --save-dev backstopjs
npx backstop init
The init command creates a configuration file and supporting directories. You can also add scripts to package.json:
{
"scripts": {
"visual:init": "backstop init",
"visual:reference": "backstop reference",
"visual:test": "backstop test",
"visual:approve": "backstop approve"
}
}
Then run npm run visual:reference to create initial references, npm run visual:test after a change, and npm run visual:approve only after you have reviewed and accepted the intended appearance.
Local npm or Docker?
A local installation is straightforward when the test machine already has a compatible browser environment. Docker can reduce rendering variation between operating systems, including text rendering differences, but adds container and network setup. BackstopJS documents backstop test --docker; its Docker image instructions also show running the lifecycle commands with the project directory mounted at /src.
docker run --rm -v "$(pwd):/src" backstopjs/backstopjs init
docker run --rm -v "$(pwd):/src" backstopjs/backstopjs reference
docker run --rm -v "$(pwd):/src" backstopjs/backstopjs test
The documented Docker Hub image is described as BackstopJS v3 and its page notes that backstop openReport is unsupported in that image. Check the image tag and compatibility with your chosen BackstopJS version before adopting those commands. In Docker, localhost inside the browser container usually means the container itself, not your host machine. The project documentation gives host.docker.internal as an example for Mac and Windows; use the correct address for your operating system and network.
2. Configure representative WordPress scenarios
Choose pages and states where a theme, template, content, or plugin change could create a meaningful visual regression. For example, a site might cover its home page, a representative article, an archive, search results, and an important form or commerce flow. These are useful scenario ideas, not requirements imposed by BackstopJS or WordPress.
BackstopJS uses backstop.json by default and also supports JavaScript configuration. A compact example configuration is:
{
"id": "wordpress-visual-checks",
"viewports": [
{ "label": "desktop", "width": 1440, "height": 900 },
{ "label": "mobile", "width": 390, "height": 844 }
],
"scenarios": [
{
"label": "home",
"url": "http://127.0.0.1:8080/",
"selectors": ["document"],
"misMatchThreshold": 0.1
},
{
"label": "article",
"url": "http://127.0.0.1:8080/sample-post/",
"selectors": ["document"],
"misMatchThreshold": 0.1
},
{
"label": "article-header",
"url": "http://127.0.0.1:8080/sample-post/",
"selectors": ["header.site-header", "main article"],
"misMatchThreshold": 0.1
}
],
"paths": {
"bitmaps_reference": "backstop_data/bitmaps_reference",
"bitmaps_test": "backstop_data/bitmaps_test",
"engine_scripts": "backstop_data/engine_scripts",
"html_report": "backstop_data/html_report",
"ci_report": "backstop_data/ci_report"
},
"report": ["browser", "CI"],
"engine": "puppeteer",
"engineOptions": {
"args": ["--no-sandbox"]
},
"asyncCaptureLimit": 5,
"asyncCompareLimit": 50,
"debug": false,
"debugWindow": false
}
This example uses a local site URL and representative selectors; adapt both to the WordPress installation and BackstopJS version you actually run. Keep only configuration keys supported by your pinned version. BackstopJS treats document as a full-document capture and viewport as the current viewport. Other CSS selectors let you capture a region or component. Full-page and region captures answer different questions: full-page captures can expose layout shifts lower down, while a region keeps the comparison focused.
Scenarios can also describe interactions, such as clicks or hover states, when a menu or other page state requires user input. Configure the scenario so the interaction happens consistently before capture. For a production-versus-staging comparison, the project supports a scenario referenceUrl; decide which environment represents the desired baseline before creating references.
3. Create references, test changes, and review the report
- Start the local or staging WordPress environment and confirm each target URL is reachable from the machine or container running BackstopJS.
- Run
backstop referenceonce the site is in the expected state. This creates the approved baseline screenshots. - Make a relevant theme, plugin, template, content, or CSS change.
- Run
backstop test. BackstopJS captures the configured scenarios again and compares the results with the references. - Inspect the visual report. Classify each difference as an intended design change, a likely defect, or unstable content/environment noise.
- Fix defects or stabilize noisy scenarios. If the new appearance is intended, run
backstop approveto replace the baseline for future comparisons.
A difference is a review signal, not proof of a defect. Approval is consequential: it replaces the references, so it can make an unwanted change the new expected appearance if used without review.
4. Make dynamic WordPress pages stable
Visual comparisons work best when repeated captures see the same page state. Rotating banners, timestamps, randomized recommendations, changing ad slots, remote widgets, and asynchronous content can create diffs unrelated to a code change. Prefer predictable test data or a static data stub where possible. BackstopJS documents readySelector, readyEvent, and delay for capture timing:
readySelector: wait for a reliable element that appears when the page or component is ready.readyEvent: wait for an application console event emitted after rendering is complete.delay: wait a fixed interval when there is no better readiness signal. This is simple but can be slow or insufficient when load time varies.hideSelectors: hide unpredictable elements while preserving their layout flow.removeSelectors: remove elements from the test DOM, which can change layout because their space is removed.
Use hide or remove rules narrowly. Hiding a changing date may remove noise while preserving layout; removing a large widget may cause the page to reflow and conceal a layout issue. Avoid masking the region whose behavior you intend to test.
{
"label": "article-with-async-content",
"url": "http://127.0.0.1:8080/sample-post/",
"selectors": ["document"],
"readySelector": ".entry-content",
"delay": 500,
"hideSelectors": [".live-view-count", ".rotating-promo"],
"removeSelectors": [".third-party-chat-widget"]
}
Use an actual readiness selector from your theme or application. The selector and delay above are examples and may need to be changed or removed for your site.
5. Set thresholds, dimensions, and viewports deliberately
misMatchThreshold sets the tolerated percentage of image difference; the documented default is 0.1. Start with the default, inspect actual reports, and change the threshold only when you understand the differences it will tolerate. A larger threshold can conceal a real visual regression. requireSameDimensions controls whether changed screenshot dimensions are accepted; the documented default is true. Keep dimension checks enabled when page or viewport size changes should fail the test.
Use the viewports that represent how people use the site. Desktop and mobile are a practical starting point; add sizes or states when the layout has meaningful breakpoints. Keep viewport dimensions fixed between baseline and test runs. A scenario can target an entire document or selected elements, so you can choose whether a check should catch the whole-page appearance or a particular component.
6. Check localization and rendering assumptions for an Indian site
The BackstopJS documentation reviewed here does not specify an India setting, special Indian hosting support, or country-specific screenshot configuration. Treat regional requirements as properties of your site and test environment. If the site serves multiple languages, scripts, regions, or content variants, create scenarios for the variants that actually exist.
- Verify the test URL serves the intended language, locale, and region-specific content.
- Check that required fonts and scripts load in the browser environment, especially for non-Latin text.
- Make sure the test uses the same relevant content and plugin configuration as the environment you want to validate.
- Check date, currency, and other localized formatting only if the site presents those values.
- Confirm the local or staging host is reachable from the browser process, including from a container if using Docker.
These are practical checks to apply to a particular site, not BackstopJS requirements or claims about every Indian WordPress installation.
7. Run reliably in CI and share results
Consistency matters because browsers can render text and other details differently across environments. The BackstopJS project documents Docker as a way to reduce some cross-platform differences and recommends matching the BackstopJS image version used by a team. In CI, remove interactive terminal options such as -t from Docker commands when output is piped or no TTY is available. Matching the container user to the host user can also prevent generated files from ending up with awkward ownership.
The project documents JUnit and other report options, and the CLI returns exit code 0 when tests succeed and 1 when they fail. Configure CI to preserve the report artifacts so reviewers can inspect failed comparisons. Report access depends on the runtime: the cited Docker Hub image documentation says openReport is not supported in that image, so use a report option supported by the selected installation and image.
8. Troubleshoot common failures
| Symptom | Likely cause | What to check or change |
|---|---|---|
| Navigation fails or the screenshot is blank | The target is unreachable from the browser process, the server is not ready, or a container URL points to the container itself. | Open the URL from the test environment. Start WordPress first and use the host/container address appropriate to your setup; do not assume localhost works inside Docker. |
| Images, fonts, or page sections are missing | Assets have not loaded by capture time, or the environment cannot reach the asset host. | Check browser/network access and use a reliable readiness selector or event. Use a delay only when needed, and keep it long enough for the expected state. |
| Every run reports differences in the same region | Content is changing between captures, such as a timestamp, rotating promotion, or remote widget. | Use deterministic test data where possible. Otherwise hide the changing element while preserving layout, or remove it only if its layout space should not be tested. |
| Text differs between a developer machine and CI | Different operating systems, browser dependencies, or fonts can change rendering. | Use a consistent, pinned runtime such as the same Docker image across environments, and verify that the required fonts are available. |
| Tests fail after a deliberate redesign | The baseline still represents the old appearance. | Review the report and confirm the redesign is expected, then run backstop approve to update references. |
| A mismatch is ignored but a visible issue remains | The tolerance may be too high, or the selected capture region excludes the affected area. | Review misMatchThreshold, selectors, and dimensions. Lower tolerance or widen the capture if that better matches the intended check. |
| Docker-generated files have awkward ownership | The container runs as a different user from the host account. | Follow the project’s container-user guidance and align the container user with the host where appropriate. |
| CI fails because no terminal is available | The Docker command requests an interactive TTY in a non-interactive job. | Remove the -t option from the Docker command template in CI. |
| The report command is unavailable in the image | The selected Docker image does not support backstop openReport. |
Use a report method supported by that image or run with a compatible local installation; confirm the image’s current documentation. |
9. Performance, reliability, and cost
BackstopJS performance depends on how many scenarios and viewports you capture, page load time, and the configured capture and comparison concurrency. Keep the suite focused on representative templates and important states, then add scenarios when they cover a distinct risk. A fixed delay for every page adds directly to run time; readiness signals and stable test data can avoid waiting longer than necessary. The configuration’s asynchronous capture and comparison limits can be tuned for the available machine, but excessive parallelism can compete for memory and browser resources.
For reliability, keep the BackstopJS version, browser/container environment, viewport sizes, and test data stable. Preserve reports from CI failures and review visual diffs before approving new baselines. BackstopJS is software run in your own environment; the cited documentation does not establish a per-screenshot service price or benchmark, so estimate costs from your own CI/container usage and maintenance needs.
10. Or skip the browser setup
If you need screenshots from URLs without maintaining a browser capture environment, ScreenshotNeo is a website screenshot API and MCP server. It returns PNG, JPEG, WebP, or PDF from one GET request. Read the ScreenshotNeo API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.in -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.in"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.in' });
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);
Replace YOUR_API_KEY with your key and use the URL you want to capture. ScreenshotNeo removes known cookie and consent banners, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. ScreenshotNeo produces captures; use BackstopJS or another comparison workflow when you need approved visual baselines and regression reports.
Create a free ScreenshotNeo account for 1,000 screenshots a month, with no card required.
FAQ
How do I use BackstopJS with WordPress?
Run BackstopJS against local or staging WordPress URLs, define scenarios for representative pages and viewports, create references, and compare after relevant changes. It does not require a WordPress-specific workflow in the documented setup.
How do I create reference screenshots and compare them after a theme or plugin change?
Run backstop reference to establish the current appearance, make the change, then run backstop test. Review the report and approve only intentional changes with backstop approve.
How can I stop dynamic content from causing flaky screenshot tests?
Prefer predictable test data. Use readiness settings for asynchronous rendering and hide or remove only the specific regions that cannot be stabilized.
Do I need Docker to run BackstopJS?
No. Project-local npm installation is documented. Docker is an optional way to make the browser environment more consistent, with networking and container setup tradeoffs.
Does BackstopJS need a WordPress plugin?
The reviewed BackstopJS documentation describes a general webapp testing tool and does not document a WordPress plugin requirement.
What should I check for an Indian WordPress site?
Test the languages, fonts, content variants, and regional formatting that the site actually serves, and confirm the test browser can reach the required assets. There is no India-specific BackstopJS setting documented in the sources reviewed.


