ScreenshotNeo

BlogHow-to

How to Add Visual Testing to Mobile App Tests

Add screenshot checks to mobile tests, choose a workflow, manage baselines, and diagnose visual diffs across Android devices.

By the ScreenshotNeo team4 October 20268 min read

Visual testing adds an image comparison to your existing mobile tests: render a known screen, compare it with an approved reference image, and inspect any difference before deciding whether it is a UI regression or an intended change. For Android Compose UI, Android Developers recommends screenshot testing to verify visual attributes. For a user-driven flow, Maestro provides assertScreenshot; for Android instrumentation screenshots collected across hosted devices, Firebase Test Lab can process and present screenshot artifacts with test results.

Start with a few important, deterministic screens. Keep the app state, device configuration, and rendering conditions consistent; then expand coverage to the device and OS combinations your users actually need. A screenshot mismatch is evidence to investigate, not by itself proof of a defect.

1. Choose the visual test level

Approach Best fit What it checks
Framework or component screenshot test Rendered UI attributes, especially Android Compose screens A captured rendering against a reference image
UI automation with Maestro An end-user flow spanning screens and interactions The current screen at a chosen point in the flow against a known-good image
Android instrumentation plus Firebase Test Lab Collecting screenshot artifacts while tests run on selected Android devices Test outcomes and captured screenshots across a chosen device matrix

These approaches can complement each other. A component-level check can localize a rendering change; a flow-level check can catch a problem that appears only after navigation or user interaction. The verified material here does not establish a current native iOS screenshot-testing setup, so use the current Apple/Xcode documentation for an iOS-native implementation rather than extrapolating Android steps.

2. Add a screenshot check to an Android UI test

Use the Android Developers screenshot-testing guide for the current setup and framework-specific commands. Its guidance describes comparing screenshots and recommends screenshot testing for verifying visual attributes in Compose UIs. The retrieved documentation does not establish version-specific dependency coordinates or a single universal test API, so avoid copying guessed setup commands: follow the guide for your Compose, test framework, and build versions.

  1. Choose a screen with user or business importance, such as sign-in, checkout, or a core dashboard.
  2. Make the screen state repeatable: control test data, account state, navigation path, and any content that changes with time.
  3. Capture the screen under a fixed device configuration and establish an approved reference image.
  4. Run the same test after changes and compare the new rendering with that reference.
  5. Review both images and the execution configuration before accepting a new baseline.

Keep reference images named for both screen and scenario, for example checkout-empty-cart or profile-signed-in. Store enough context with the test or its documentation to identify the device size, orientation, locale, and relevant state represented by the image.

3. Add a visual assertion with Maestro

Maestro’s assertScreenshot compares the current screen with a known-good image. It accepts a reference path, an optional cropOn selector, and an optional thresholdPercentage. The documented default threshold is 95.0 percent. Choose a threshold deliberately for the screen and review diffs; the default is a tool setting, not a universal standard. See the Maestro assertScreenshot reference.

appId: com.example.app
---
- launchApp
- tapOn: "Profile"
- assertScreenshot:
    path: "screenshots/profile.png"
    thresholdPercentage: 95

This flow assumes the app exposes a visible “Profile” control and that screenshots/profile.png is the known-good reference in the location Maestro resolves for the flow. Adapt the app ID, interaction, and reference path to your project. If you use cropOn, ensure the reference image was cropped to the same element in the same way; otherwise the compared regions will not correspond.

Picking a threshold and crop

  • Begin with the documented default unless you have a reason to change it, then evaluate actual diffs from your app and devices.
  • A stricter match can expose small changes but may report more rendering variation. A looser match can tolerate variation while overlooking some changes.
  • Use a crop when only one stable region matters, such as a price or status area. Avoid cropping away the content whose appearance the test is meant to protect.
  • Keep threshold and crop choices visible in the flow or test documentation so a later maintainer understands the comparison.

4. Capture Android screenshots in Firebase Test Lab

Firebase Test Lab’s Android instrumentation workflow uses AndroidX screenshot capture and the Firebase Test Lab screenshot-processing library. The documented workflow is to add the dependency, register FirebaseScreenCaptureProcessor, capture screenshots in tests, build the app and test APKs, run the test, and inspect screenshots alongside results. Follow the current Firebase instrumentation screenshot guide for exact dependency and registration details.

  1. Set up the screenshot capture and processor as shown in the Firebase guide for your project.
  2. Capture screenshots during relevant instrumentation tests.
  3. Build both the app APK and the test APK.
  4. Run the instrumentation test in Test Lab and open the test results to review captured screenshots.
  5. Use a deliberate matrix of device models and configurations rather than expanding it without regard to your supported audience.

Test Lab matrices let you select device models and configurations such as OS version, orientation, and locale. The Firebase Test Lab getting-started guide describes Android device testing and result artifacts. Firebase’s troubleshooting guidance cautions that screenshot-diff tests can be more brittle on some device types and recommends Arm emulator devices for them; treat that as Firebase-specific guidance, not a guarantee for every test stack.

5. Make references reliable and reviewable

Control the screen before capture

  • Wait for the content under test to appear before capturing. Avoid relying on arbitrary timing when the test framework can wait for a visible condition.
  • Use fixed or seeded test data. Remove dependence on live feeds, personalized content, random values, and changing timestamps where possible.
  • Set a consistent device model or emulator profile, OS version, orientation, locale, font scale, and display settings for baseline creation and comparison.
  • Handle animations and transitions so captures occur at the same visual point. If they cannot be controlled, capture a stable region or state.
  • Keep network-dependent screens deterministic, for example by using test fixtures or a controlled test backend.

Review every mismatch before updating a baseline

  1. Open the expected and actual images together, and inspect the diff if the tool provides one.
  2. Confirm the test reached the intended screen and state.
  3. Check device, OS, orientation, locale, and other rendering settings against the baseline context.
  4. Determine whether the visual change is intended, a product defect, or environmental variation.
  5. Update the reference only when the changed appearance is approved; record the reason in the same change review.

Do not automatically replace references whenever a test fails. That can turn a real regression into the new expected result. Conversely, do not treat every pixel difference as a user-visible defect: inspect its location and cause.

6. Expand coverage without making the suite noisy

Start with a short list of high-value screens and states rather than attempting to snapshot every view. Add a case when it covers a distinct layout, important state, or supported configuration that could plausibly break independently. For device coverage, prioritize the models, OS versions, orientations, and locales that match your app’s supported audience. A broad hosted matrix can increase execution time and result volume, so use it where cross-device rendering confidence is valuable.

Keep the visual assertion beside the test that establishes the relevant state. This makes a failed image easier to interpret and prevents a screenshot from becoming detached from the navigation and data setup that produced it.

7. Troubleshooting visual test failures

Symptom Likely cause What to check
Many pixels differ on every run Nondeterministic content, animation timing, or inconsistent rendering configuration Stabilize test data and capture timing; compare device, OS, locale, orientation, and display settings.
The screenshot shows the previous screen or a loading state The test captured before navigation or content settled Wait for a screen-specific element or state before asserting the image.
A cropped Maestro assertion fails unexpectedly The reference and current crop do not represent the same area Check the selector and recreate the reference with the same crop behavior.
Small rendering changes trigger failures The selected threshold is too strict for the observed environment, or the environment varies First stabilize the environment; then review whether a documented threshold adjustment is appropriate.
A visual change is accepted but later causes a defect The baseline was updated without reviewing the product impact Require image review and an explanation for each intentional baseline change.
Firebase screenshot diffs are brittle on a device type Screenshot-diff behavior can vary by device type Consult the Firebase Test Lab troubleshooting FAQ; Firebase recommends Arm emulator devices for screenshot-diff tests.
Test Lab results contain no expected screenshots Capture processor, test capture call, APK build, or result inspection may not follow the documented workflow Verify each setup step against the current Firebase instrumentation screenshot guide and inspect the correct test result.

8. Performance, reliability, and cost considerations

Screenshot comparisons add capture and image-processing work to a test, and hosted device matrices multiply executions by the configurations selected. The dossier provides no timing or pricing benchmarks, so measure suite duration and cloud usage in your own pipeline. Keep expensive matrix runs focused on meaningful configurations, and run smaller, fast checks more frequently if your CI setup supports that split.

Reliability comes primarily from deterministic state and consistent rendering conditions. A stable local baseline does not prove every supported device renders identically; matrix testing can reveal device-specific issues, while excessive matrix breadth can create slow, noisy results. Track baseline updates as code changes and preserve enough execution context to reproduce a mismatch.

Or skip the browser setup

If your mobile test workflow also needs screenshots of web pages, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF, and the parameter names used by other screenshot APIs also work. It is for web-page captures; it does not replace native app screenshot testing.

Use the ScreenshotNeo API docs for the complete options and response details. A basic cURL request looks like this:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The same request in Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

And Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  • Cookie and consent banners are accepted and removed before capture; newsletter popups and chat widgets are removed too. Each of these steps can be turned off.
  • Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. Responses include X-Page-Verdict and X-Billed headers to show the outcome.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
  • The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is available on every plan.

Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.

FAQ

Should every mobile screen have a screenshot test?

No. Cover screens and states where visual regressions matter, then add cases when they protect a distinct layout or supported configuration.

Does a passing screenshot test prove the app is accessible?

No. Image matching checks rendered appearance against a reference; it does not establish accessibility semantics or interaction behavior.

Can I use ScreenshotNeo to test native app screens?

No. ScreenshotNeo captures websites. Use your mobile framework or UI automation tool for native app screenshots; ScreenshotNeo can capture web pages used by your product or tests.

Sources