Skip to main content

Visual Testing

What can it do?

WebdriverIO provides image comparisons on screens, elements or a full-page for

  • 🖥️ Desktop browsers (Chrome / Firefox / Safari / Microsoft Edge)
  • 📱 Mobile / Tablet browsers (Chrome on Android emulators / Safari on iOS Simulators / Simulators / real devices) via Appium
  • 📱 Native Apps (Android emulators / iOS Simulators / real devices) via Appium (🌟 NEW 🌟)
  • 📳 Hybrid apps via Appium

through the @wdio/visual-service which is a lightweight WebdriverIO service.

This allows you to:

  • save or compare screens/elements/full-page screens against a baseline
  • automatically create a baseline when no baseline is there
  • block out custom regions and even automatically exclude a status and or toolbars (mobile only) during a comparison
  • increase the element dimensions screenshots
  • hide text during website comparison to:
    • improve stability and prevent font rendering flakiness
    • only focus on the layout of a website
  • use different comparison methods and a set of additional matchers for better readable tests
  • verify how your website will support tabbing with your keyboard), see also Tabbing through a website
  • and much more, see the service and method options

The service is a lightweight module to retrieve the needed data and screenshots for all browsers/devices. The comparison power comes from ResembleJS. If you want to compare images online you can check the online tool.

NOTE For Native/Hybrid Apps

The methods saveScreen, saveElement, checkScreen, checkElement and the matchers toMatchScreenSnapshot and toMatchElementSnapshot can be used for Native Apps/Context.

Please use the property isHybridApp:true in your service settings when you want to use it for Hybrid Apps.


The easiest way is to keep @wdio/visual-service as a dev-dependency in your package.json, via:

npm install --save-dev @wdio/visual-service


@wdio/visual-service can be used as a normal service. You can set it up in your configuration file with the following:

import path from 'node:path'

// wdio.conf.ts
export const config = {
// ...
// =====
// Setup
// =====
services: [
['visual', {
// Some options, see the docs for more
baselineFolder: path.join(process.cwd(), 'tests', 'baseline'),
formatImageName: '{tag}-{logName}-{width}x{height}',
screenshotPath: path.join(process.cwd(), 'tmp'),
savePerInstance: true,
// ... more options
// ...

More service options can be found here.

Once set up in your WebdriverIO configuration, you can go ahead and add visual assertions to your tests.

WebdriverIO MultiRemote

We also support MultiRemote. To make this work properly make sure that you add wdio-ics:options to your capabilities as you can see below. This will make sure that each screenshot will have its own unique name.

Writing your tests will not be any different in comparison to using the testrunner

// wdio.conf.js
export const config = {
capabilities: {
chromeBrowserOne: {
capabilities: {
browserName: 'chrome',
'goog:chromeOptions': {
args: ['disable-infobars'],
// THIS!!!
'wdio-ics:options': {
logName: 'chrome-latest-one',
chromeBrowserTwo: {
capabilities: {
browserName: 'chrome',
'goog:chromeOptions': {
args: ['disable-infobars'],
// THIS!!!
'wdio-ics:options': {
logName: 'chrome-latest-two',

Running Programmatically

Here is a minimal example of how to use @wdio/visual-service via remote options:

import { remote } from 'webdriverio'
import VisualService from '@wdio/visual-service'

let visualService = new VisualService({
autoSaveBaseline: true

const browser = await remote({
logLevel: 'silent',
capabilities: {
browserName: 'chrome',

// "Start" the service to add the custom commands to the `browser`

await browser.url('')

// or use this for ONLY saving a screenshot
await browser.saveFullPageScreen('examplePaged', {})

// or use this for validating. Both methods don't need to be combined, see the FAQ
await browser.checkFullPageScreen('examplePaged', {})

await browser.deleteSession()

Tabbing through a website

You can check if a website is accessible by using the keyboard TAB-key. Testing this part of accessibility has always been a time-consuming (manual) job and pretty hard to do through automation. With the methods saveTabbablePage and checkTabbablePage, you can now draw lines and dots on your website to verify the tabbing order.

Be aware of the fact that this is only useful for desktop browsers and NOT** for mobile devices. All desktop browsers support this feature.


The work is inspired by Viv Richards his blog post about "AUTOMATING PAGE TABABILITY (IS THAT A WORD?) WITH VISUAL TESTING".

The way tabbable elements are selected is based on the module tabbable. If there are any issues regarding the tabbing please check the and especially the More Details section.

How does it work

Both methods will create a canvas element on your website and draw lines and dots to show you where your TAB would go if an end-user would use it. After that, it will create a full-page screenshot to give you a good overview of the flow.


Use the saveTabbablePage only when you need to create a screenshot and DON'T want to compare it with a baseline image.

When you want to compare the tabbing flow with a baseline, then you can use the checkTabbablePage-method. You DON'T need to use the two methods together. If there is already a baseline image created, which can automatically be done by providing autoSaveBaseline: true when you instantiate the service, the checkTabbablePage will first create the actual image and then compare it against the baseline.


Both methods use the same options as the saveFullPageScreen or the compareFullPageScreen.


This is an example of how the tabbing works on our guinea pig website:

WDIO tabbing example

Typescript support

We now also support typescript types. Add the following to the types in your tsconfig.json:

"compilerOptions": {
"types": ["@wdio/visual-service"]

System Requirements

Aside from the general project requirements this module relies on Canvas which is a canvas implementation for Node.js. It relies on Cairo.

By default, binaries for macOS, Linux and Windows will be downloaded during your project's npm install. If you don't have a supported OS or processor architecture, the module will be compiled on your system. This requires several dependencies, including Cairo and Pango.

For detailed installation information, see the node-canvas wiki. One-line installation instructions for common OSes are below. Note that libgif/giflib, librsvg and libjpeg are optional and only required if you need GIF, SVG and JPEG support, respectively. Cairo v1.10.0 or later is required.

Using Homebrew:

brew install pkg-config cairo pango libpng jpeg giflib librsvg pixman

Mac OS X v10.11+: If you have recently updated to Mac OS X v10.11+ and are experiencing trouble when compiling, run the following command: xcode-select --install. Read more about the problem on Stack Overflow. If you have Xcode 10.0 or higher installed, to build from source you need NPM 6.4.1 or higher.

Welcome! How can I help?

WebdriverIO AI Copilot