In Appium, which request captures a still screenshot on Android and on iOS?
answer
- inherited from the protocol, not invented
- same call, both drivers
- base64, not bytes
- whole screen, no element tree
- GET /session/:sessionId/screenshot
basics
~10 sBoth platforms answer the same W3C request, GET /session/:sessionId/screenshot, and return the whole screen as a base64-encoded PNG. Appium's UiAutomator2 driver on Android and its XCUITest driver on Apple platforms behave identically here.
solid answer
~40 sThe still screenshot is inherited from the W3C WebDriver protocol, so it is the one capture command that does **not** diverge: `GET /session/:sessionId/screenshot` returns a base64-encoded PNG of the whole screen on an Android UiAutomator2 session and on an Apple XCUITest session alike. Everything around it does diverge. The UiAutomator2 driver declares extras in its own execute-method map, including `mobile: screenshots` and `mobile: viewportScreenshot`; XCUITest's settings reference declares `screenshotQuality`, `screenshotOrientation` and `webScreenshotMode`. Video is a different command on each platform again. So a cross-platform harness for a cattle-auction bidding app can attach a failure image with one shared call, but must branch the moment it wants anything richer than a still.
code
python · 13 linesfrom appium import webdriver
from appium.options.android import UiAutomator2Options
options = UiAutomator2Options()
options.automation_name = "UiAutomator2"
options.app = "/builds/cattle-auction.apk"
driver = webdriver.Remote("http://127.0.0.1:4723", options=options)
try:
driver.find_element("accessibility id", "place-bid").click()
driver.get_screenshot_as_file("cattle-auction-bid.png")
finally:
driver.quit()go deeper
Be ready to name the request and its payload without hedging: GET /session/:sessionId/screenshot, base64-encoded PNG, whole screen, identical on Android and Apple sessions.
Explain why this one command is portable while recording is not: the still comes from the W3C protocol, the recorders come from each driver's own execute-method map.
Show how a failure handler captures safely in production: inside the live session, decoded before writing, and budgeted rather than fired after every single step in a wide parallel run.
Own the tradeoff between artefact richness and run cost across a fleet, and be clear that a still is the cheapest evidence available while video and streaming carry per-platform mechanisms and per-platform failure modes.
## The still image is the one thing that does not diverge Appium is a W3C WebDriver server, so the screenshot command is inherited from the protocol rather than invented per platform. A test issues `GET /session/:sessionId/screenshot` and the server answers with a JSON body whose `value` is a **base64-encoded PNG** of the whole screen. That holds for an Android session driven by the UiAutomator2 driver and for an Apple session driven by the XCUITest driver: same route, same encoding, same response shape. Language clients wrap it in a helper, but underneath every one of them issues that request. This matters because almost nothing else about evidence capture in Appium is portable. Video, live streaming and audio are each answered by a **different execute method on a different driver**, and any helper that captures them has to branch on `platformName`. The still screenshot is the exception, and it is why a cross-platform suite for a cattle-auction bidding app can attach a "what the run saw" image on both platforms from one line of shared code. ## What the call actually returns - The payload is the **whole screen**, not just the application window: status bars, notification shades and any system dialog drawn over the auction lot list all appear in it. - It is a **PNG**, base64-encoded inside the JSON envelope, so a large device screen becomes a sizeable string; capturing after every step is real bytes over the wire. - It is a snapshot of the display, so an in-flight animation or a half-drawn bid list is captured mid-flight. - It carries **no element metadata**. If you need the tree, that is `GET /session/:sessionId/source`, a different command. - Appium's route tables spell the session placeholder `:sessionId`. `/session/:id/screenshot` is not the form the server documents. ## What each driver adds on top The common call is the floor, not the ceiling. Each driver declares extras in its own execute-method map or settings reference, and those are **not** shared: | Concern | Android (UiAutomator2 / the Android drivers) | Apple (XCUITest) | |---|---|---| | Standard still | `GET /session/:sessionId/screenshot` | `GET /session/:sessionId/screenshot` | | Extra still commands | `mobile: screenshots`, `mobile: viewportScreenshot` | `mobile: source` for the tree, not the image | | Named tuning settings | `mjpegServerScreenshotQuality`, `mjpegBilinearFiltering` | `screenshotQuality`, `screenshotOrientation`, `webScreenshotMode` | | Video | `mobile: startMediaProjectionRecording` | `mobile: startXCTestScreenRecording`, `mobile: startScreenRecording` | `mobile: screenshots` and `mobile: viewportScreenshot` are declared in the **UiAutomator2 driver's own** execute-method map, alongside `mobile: viewportRect`; they let an Android session ask for per-display images or for the viewport region rather than the whole display. XCUITest's settings reference declares `screenshotQuality` and `screenshotOrientation`, which change how the still is produced on Apple platforms. Attributing one of these to the wrong driver is the classic mistake here, and no spell-check catches it because every identifier involved is real. ## Where the still stops being enough A single PNG answers "what was on screen when the assertion failed". It does not answer: 1. What happened in the three seconds before the failure — that needs a recording. 2. Whether the element existed but sat off-screen — that needs the page source. 3. Why a tap landed on the wrong auction lot — that usually needs the element tree and a video together. That is why a serious Appium harness pairs the screenshot with a platform-specific recording, and why "we take screenshots" should be read as the beginning of an evidence story rather than the whole of it. ## Failure modes worth recognising - Calling the command **after** the session ends. `DELETE /session/:sessionId` invalidates the id, so the capture has to happen inside the failure handler while the session is still alive. - Writing the base64 string straight to disk without decoding it, producing a "corrupt" PNG that is really a text file. - Capturing on every step across a large parallel run and being surprised by the artefact volume; the encoding cost is paid per call. - Treating the image as proof of visibility. On Apple platforms an element can be present in the tree and rendered under another view; the picture shows the composite, not the hierarchy. - Expecting two runs of the same screen to produce byte-identical images. A clock and a battery indicator differ every time, which is why comparing images is a separate discipline from capturing them. The summary a junior should be able to give: one request, both platforms, base64 PNG of the whole screen — and everything richer than that is per driver.
- The image comes back as a base64 string. What does a harness have to do before it is a usable artefact?Decode it. The JSON `value` is base64 text, so the harness must base64-decode it and write the resulting bytes as a binary file. Most language clients expose a helper that does the decode and the write for you; skipping the decode is how teams end up with PNG files that no viewer will open.
- Why can the screenshot succeed while a video capture on the same Android session returns nothing?They are different mechanisms. The still is a W3C command the driver answers directly; the Android video is produced by the `io.appium.settings` helper application through media projection, and its payload only comes back from `mobile: stopMediaProjectionRecording`. A working screenshot therefore proves the session is alive, not that recording is wired up.
saying these in an interview costs you the question
- Says the screenshot endpoint differs between Android and iOS
- Expects raw PNG bytes rather than a base64-encoded string
- Thinks the driver saves the image to device storage and returns a path
- Assumes the capture is limited to the app window, excluding system bars
- Attributes mobile: viewportScreenshot to the XCUITest driver
- Believes a screenshot proves an element was visible and hittable