ScreenshotNeo

BlogHow-to

How to Take Screenshots in Appium Java

Capture Appium screenshots in Java, save durable files, capture elements, return Base64 or bytes, and fix common platform errors.

By the ScreenshotNeo team1 October 20266 min read

Use Selenium’s TakesScreenshot interface: cast the Appium driver, call getScreenshotAs(OutputType.FILE), and copy the temporary file to a permanent path.

File source = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
Files.copy(source.toPath(), Paths.get("artifacts", "screen.png"), StandardCopyOption.REPLACE_EXISTING);

OutputType.FILE creates a temporary file, so copy it immediately if your test report or CI job must retain it. You can also request Base64 or raw bytes, and Selenium exposes the same screenshot method on supported elements.

1. Prerequisites and driver setup

You need an Appium server, a connected Android or iOS device (or emulator/simulator), the Appium Java client, and Selenium Java dependencies. The driver must already be created before taking a screenshot. A minimal Android session looks like this:

import io.appium.java_client.android.AndroidDriver;
import java.net.MalformedURLException;
import java.net.URL;
import org.openqa.selenium.remote.DesiredCapabilities;

DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("platformName", "Android");
caps.setCapability("appium:automationName", "UiAutomator2");
caps.setCapability("appium:deviceName", "Android Emulator");
caps.setCapability("appium:appPackage", "com.example.app");
caps.setCapability("appium:appActivity", ".MainActivity");

AndroidDriver driver = new AndroidDriver(
    new URL("http://127.0.0.1:4723"), caps
);

For iOS, use IOSDriver and the capabilities required by XCUITest. Screenshot behavior is scoped to the current context: Appium describes native capture as the viewport and web-context capture as the window.

2. Save a full driver screenshot to a durable file

Create the destination directory, capture the temporary file, then copy it. This version is safe for repeated test runs because it replaces an existing artifact.

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;

Path target = Paths.get("artifacts", "login-failure.png");
Files.createDirectories(target.getParent());

File temp = ((TakesScreenshot) driver)
    .getScreenshotAs(OutputType.FILE);
Files.copy(
    temp.toPath(),
    target,
    StandardCopyOption.REPLACE_EXISTING
);

Use a unique filename when tests run in parallel. Include the test name, device, context, and timestamp, or write each test into its own worker directory.

String name = "login-" + System.currentTimeMillis() + ".png";
Path target = Paths.get("artifacts", name);
Files.createDirectories(target.getParent());
File temp = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
Files.copy(temp.toPath(), target, StandardCopyOption.REPLACE_EXISTING);

3. Choose FILE, BASE64, or BYTES

Output type Result Use it when
OutputType.FILE Temporary File You will archive or attach an image; copy it immediately.
OutputType.BASE64 Base64-encoded PNG string Your report system embeds images as text or data URLs.
OutputType.BYTES Raw PNG bytes You upload directly to object storage or process bytes in memory.

Return Base64 for a test report

String pngBase64 = ((TakesScreenshot) driver)
    .getScreenshotAs(OutputType.BASE64);

String dataUrl = "data:image/png;base64," + pngBase64;

Write raw bytes

byte[] png = ((TakesScreenshot) driver)
    .getScreenshotAs(OutputType.BYTES);
Files.write(Paths.get("artifacts", "screen.png"), png);

All three forms represent the screenshot returned by the driver. The image is normally PNG data; do not assume that changing the filename changes its encoding.

4. Capture one element

Selenium defines WebElement as a TakesScreenshot subinterface. Find the element, cast it, and call the same method.

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

WebElement panel = driver.findElement(By.id("error-panel"));
File elementFile = ((TakesScreenshot) panel)
    .getScreenshotAs(OutputType.FILE);
Files.copy(
    elementFile.toPath(),
    Paths.get("artifacts", "error-panel.png"),
    StandardCopyOption.REPLACE_EXISTING
);

Element capture is useful for assertions and focused diagnostics. If the element is outside the visible viewport, hidden, covered, or not yet rendered, wait for it and make sure its layout has nonzero dimensions before capturing.

5. A reusable helper for tests

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;

public final class Screenshots {
  private Screenshots() {}

  public static Path save(WebDriver driver, Path destination)
      throws IOException {
    Files.createDirectories(destination.getParent());
    Path temp = ((TakesScreenshot) driver)
        .getScreenshotAs(OutputType.FILE).toPath();
    Files.copy(temp, destination, StandardCopyOption.REPLACE_EXISTING);
    return destination;
  }
}

Call it from a failure hook, for example after catching an assertion error. Keep screenshot capture in a separate error path so a failed screenshot does not hide the original test failure.

6. Native and web contexts

In a native context, the image covers the device viewport. In a web context, it covers the current web window. If your test switches between contexts, capture after switching to the context whose pixels you need.

for (String context : driver.getContextHandles()) {
  driver.context(context);
  Path target = Paths.get("artifacts", context + ".png");
  Screenshots.save(driver, target);
}

Web-context screenshots do not automatically produce a complete, vertically stitched page. If you need a full web page, use a browser tool designed for full-page capture or capture and stitch sections yourself.

7. Timing, waits, and reliable evidence

  • Wait for the state you want to document, such as a visible error panel or a completed navigation.
  • Capture after animations or transitions finish when they change the pixels under test.
  • Use deterministic device size, orientation, font scale, and theme settings in CI.
  • Save screenshots on failure and include the current URL, activity, context, and test name in the artifact metadata.
  • For parallel workers, use isolated paths to avoid two tests replacing the same file.

A screenshot call captures the current rendered surface; it does not wait for an assertion condition, network idle, or animation completion on your behalf.

8. Troubleshooting common failures

Symptom Likely cause Fix
WebDriverException The driver or platform failed to provide an image. Check the Appium server log, device connection, current session, and driver implementation. Retry only after addressing the underlying session problem.
UnsupportedOperationException The active driver does not implement screenshots. Use a driver/platform that supports TakesScreenshot, or capture through a platform-specific alternative.
Android capture is rejected The app window uses Android FLAG_SECURE. Remove or change that security flag in a test build if policy permits. A client-side cast cannot override it.
Image is blank or has zero dimensions The surface has not rendered, the element is hidden, or the device reports zero-size content. Wait for visibility and layout, verify the current context, and inspect device state before capturing.
File disappears after the test OutputType.FILE points to a JVM temporary file. Copy it immediately to an artifacts directory.
Element cast fails The element implementation does not support screenshots. Capture the driver viewport, or use a supported driver and element implementation.
Wrong screen captured The test navigated, changed orientation, or switched context after the intended state. Place the call directly after the state-setting action and record context/orientation with the artifact.

9. Performance, reliability, and storage

Screenshot capture transfers image data from the device or driver to the test process, so large screens and frequent captures increase I/O and report size. Capture at failure points and important checkpoints instead of every step. Prefer BYTES for direct uploads to avoid an extra temporary-file copy, and use FILE when your test framework already archives files.

Keep artifacts on durable CI storage and apply retention rules. A screenshot is evidence of one device state; pair it with logs, source metadata, and the test name so it remains useful after the session ends.

10. Or skip the browser setup

If your goal is website screenshots rather than an Appium device surface, ScreenshotNeo provides a single HTTP request. Its API accepts a URL and returns PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation for all options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
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 banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. ScreenshotNeo also offers an MCP server for AI agents, including Claude and Cursor. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

Create a free ScreenshotNeo account to get started.

11. FAQ

Does Appium save the screenshot automatically?

No. getScreenshotAs returns a file, string, or byte array. Your test code must persist or attach the result.

Can I request JPEG instead of PNG?

The standard Appium/Selenium screenshot contract returns PNG image data. Convert it after capture if your report requires another format.

Why should I copy the temporary file immediately?

The JVM owns the temporary file and may delete it when the process exits. Copying it immediately makes the artifact durable.

Can screenshots bypass secure-screen protections?

No. Platform security controls such as Android FLAG_SECURE can reject or obscure capture.

What is the simplest API call for a website screenshot?

Use ScreenshotNeo’s GET /v1/shot request with an access key and URL; the examples above show cURL, Python, and Node.js.