Phonebox / Docs
API reference

Observe

Read the screen as numbered elements or compact text, and take screenshots with their scale.

View as Markdown

Both endpoints read the phone's screen, so the phone must be ready, and both count as activity that keeps the phone from idling, unless the key is Read-only. Observe the screen explains every field, which elements are listed, and the text form.

Observe the screen

GET /v1/phones/{id}/observe needs the phones:read scope.

Reads the screen and stores its element list as a snapshot for 15 minutes, so that actions can target elements by ref together with the snapshot_id.

ParameterTypeDefaultRules
screenshotstringnonenone, jpeg or png. Adds a screenshot to the JSON.
max_widthintegerThe screen's widthFrom 160 to 2000. The widest the screenshot may be, in pixels.
formatstringjsonjson, or text for the text form alone.
curl "https://phonebox.dev/v1/phones/ph_7kx2m6q4v3ta/observe?screenshot=jpeg&max_width=720" \
  -H "Authorization: Bearer $PHONEBOX_API_KEY"

The JSON answer is an observation. This one is shortened: data holds the image in base64.

Response: observation
{
  "snapshot_id": "snp_4f2k7m3q6z3a",
  "taken_at": "2026-09-29T10:01:05.662Z",
  "app": { "package": "com.android.launcher3", "activity": null },
  "keyboard": { "visible": false, "focused_editable": false },
  "screen": { "width": 1080, "height": 2400 },
  "elements": [
    {
      "ref": 1, "type": "EditText", "text": "Search apps", "desc": null, "id": "com.android.launcher3:id/search",
      "bounds": [60, 200, 1020, 300], "center": [540, 250], "state": ["clickable", "editable"]
    },
    {
      "ref": 2, "type": "TextView", "text": "Chrome", "desc": null, "id": "com.android.launcher3:id/icon",
      "bounds": [100, 1800, 300, 2000], "center": [200, 1900], "state": ["clickable"]
    }
  ],
  "truncated": false,
  "text": "app com.android.launcher3\nkeyboard hidden\nscreen 1080x2400\n[1] EditText \"Search apps\" #search clickable editable (540,250)\n[2] TextView \"Chrome\" #icon clickable (200,1900)",
  "screenshot": { "format": "jpeg", "width": 720, "height": 1600, "scale": 0.666667, "data": "/9j/4AAQSkZJRgABAQAAAQABAAD…" }
}

screenshot is present only when you ask for one. Element coordinates are always device pixels, and screenshot.scale is the image's width divided by the screen's. The whole answer stays under 4 MB, so Phonebox shrinks a screenshot further when it has to.

With format=text, the answer is text/plain; charset=utf-8, holding the text field alone, and its X-Snapshot-Id header carries the snapshot ID. The text form never includes a screenshot.

ErrorWhen
400 validation_failedA parameter is outside its range or given twice.

The readiness and phone-service errors in Common errors apply too.

Take a screenshot

GET /v1/phones/{id}/screenshot needs the phones:read scope.

Returns the screen as an image, not JSON.

ParameterTypeDefaultRules
formatstringpngpng or jpeg.
max_widthintegerThe screen's widthFrom 160 to 2000. The widest the image may be, in pixels.
qualityinteger70From 30 to 95. JPEG quality. A PNG ignores it.
curl -o screen.jpg "https://phonebox.dev/v1/phones/ph_7kx2m6q4v3ta/screenshot?format=jpeg&max_width=720" \
  -H "Authorization: Bearer $PHONEBOX_API_KEY"

The answer is image/png or image/jpeg, always under 4 MB. Phonebox makes the image narrower when it would be larger. Three headers describe it:

HeaderMeaning
X-Screen-WidthThe screen's width in device pixels.
X-Screen-HeightThe screen's height in device pixels.
X-Screen-ScaleThe image's width divided by the screen's, to six decimal places. Divide a point on the image by it to get device pixels.
ErrorWhen
400 validation_failedA parameter is outside its range or given twice.

The readiness and phone-service errors in Common errors apply too.

On this page