Live streaming
How the live screen works, frame rates per plan, controlling a device with taps, swipes, text and keys, and what a viewer keeps alive.
Every running device can stream its screen to you while you watch. The dashboard uses this for its live view; you can use the same WebSocket from your own code (protocol in Live stream API).
How it works#
- A viewer opens a WebSocket to
/v1/devices/:id/stream. - When the first viewer connects, AkaPhone asks the device's host to start capturing. The host sends JPEG frames, AkaPhone relays each one to every connected viewer.
- Taps, swipes, text and keys travel the other way and are executed on the device with
adb shell input. - When the last viewer disconnects, capture stops. Streaming does not cost anything beyond the device minutes.
Frames are only produced while someone is watching. To grab a single image without a stream, call GET /v1/devices/:id/screenshot.
Frame rate#
| Plan | Frames per second |
|---|---|
| Free | 2 |
| Dev | 4 |
| Team | 5 |
Frames are JPEG, downscaled by the host (540 px wide by default). When the screen does not change the host still resends a frame every 10 seconds, so a new viewer is never left blank for long. A viewer that connects gets the last frame immediately if one exists.
Input#
The same four input types work over the stream socket and over POST /v1/devices/:id/input:
| Type | Fields | Example |
|---|---|---|
tap |
x, y (device pixels, 0 to 10000) |
{"type":"tap","x":360,"y":780} |
swipe |
x1, y1, x2, y2, ms (duration, 1 to 10000, default 300) |
{"type":"swipe","x1":360,"y1":1200,"x2":360,"y2":400,"ms":250} |
text |
text (1 to 500 characters) |
{"type":"text","text":"hello@example.com"} |
key |
key: HOME, BACK, RECENTS, ENTER, DEL or TAB |
{"type":"key","key":"BACK"} |
Coordinates are in the device's own pixels (for the default pixel_8 profile, 720×1560), not in the downscaled frame. Scale clicks on a frame by device width / frame width.
Input on the socket is limited to 20 messages per second per connection. Extra messages are dropped with an error event. Long text is best sent as one text message rather than one per character.
Viewers keep a device alive#
A device with at least one open stream connection is never stopped as idle. Close the socket (or the browser tab) when you are done watching, or stop the device. If your balance runs out, the device stops anyway and viewers get device.stopped with reason credits.
Authentication#
Browsers cannot set an Authorization header on a WebSocket, so there are three ways in:
| Who | How |
|---|---|
| The dashboard | The ak_session cookie, from app.akaphone.com only. |
| Servers and scripts | Authorization: Bearer ak_live_… on the upgrade request. |
| Your own web page | Get a short-lived stream token from your backend with POST /v1/devices/:id/stream-token, then connect with ?key=<token>. Tokens work once, for one device, for 5 minutes. |
Never put a ak_live_ key in front-end code. Stream tokens exist so you do not have to.