PREVIEWAPK

PreviewAPK for developers & AI agents

Your agent wrote the code and compiled the APK. Now what? It can't run an emulator, and you don't want to install Android Studio just to look at a button. PreviewAPK gives your agent eyes and ears inside the app it builds — it pushes the build, the app runs on a cloud phone in seconds, and the agent drives it, sees its screen, reads its UI, and hears its logs. It stops building blind: it verifies its own work, and you see the feature the moment it's proven — live, in your browser.

The loop

  1. The agent builds app.apk.
  2. It pushes the build to your device (previewapk push app.apk --run).
  3. It starts the session agent-driven, navigates by the UI hierarchy (elements, not pixels), checks screenshots to verify the change visually, and reads the app's logs — a crash arrives with its reason attached.
  4. It reports back: “Built it, tested it — take a look.” You're watching the same live session in your portal; take control any time and tap around yourself.
  5. Anyone else need eyes on it? The session's view-only link is a byproduct of the loop — send it to whoever. Links never drive.

Two kinds of links

Session link/v/… — one per session, view-only. Minted when a session starts; dies when it ends. Get it from previewapk links (or the links action) once the session is live, and give it to the human: "here's the live app." There is no permanent link — a link that never expires is a leak waiting for a timestamp.

Links never drive. Driving needs credentials — you in the portal, or your API key. A session is driven by exactly one side at a time (see driver modes below).

CLI

curl -o previewapk https://previewapk.siteport.site/cli/previewapk.py && chmod +x previewapk
./previewapk setup                  # approve a short code in the portal; the key is minted
                                    # there and saved on this machine — never pasted into a chat
                                    # (manual alternative: export PREVIEWAPK_API_KEY=<key from
                                    # the portal's Developers card> — the env var wins when set)

./previewapk push app.apk --run     # upload + start, agent-driven
./previewapk look                   # compact numbered snapshot of the screen (refs you can tap)
./previewapk shot screen.png        # save a screenshot of the live screen (PNG)
./previewapk tap 0.5 0.6            # tap (0..1 screen fractions)
./previewapk text "hello"           # type into the focused field
./previewapk handoff user           # give the human the wheel
./previewapk links                  # print the share link for the live session
./previewapk stop

Every command supports --json for machine-readable output. Coordinates are resolution-independent fractions, so the same script drives any device profile.

MCP server

Give your agent native tools instead of a shell: push, start, tap, type, screenshot (returned as an image the agent can actually see), handoff, stop.

curl -o previewapk_mcp.py https://previewapk.siteport.site/mcp/previewapk_mcp.py

# Claude Code:
claude mcp add previewapk --env PREVIEWAPK_API_KEY=<key> -- python3 /path/to/previewapk_mcp.py

27 tools: previewapk_list_devices, previewapk_use_device, previewapk_status, previewapk_push_apk, previewapk_start, previewapk_stop, previewapk_get_links, previewapk_tap, previewapk_swipe, previewapk_press_key, previewapk_type_text, previewapk_relaunch, previewapk_screenshot, previewapk_handoff, previewapk_get_logs, previewapk_feedback, previewapk_hierarchy, previewapk_tap_text, previewapk_observe, previewapk_act, previewapk_wait_for, previewapk_request_human, previewapk_finish, previewapk_record_start, previewapk_record_stop, previewapk_record_download, previewapk_device. With PREVIEWAPK_API_KEY unset, the MCP server reads the key previewapk setup saved at ~/.previewapk/credentials.json — one setup covers both clients.

When the network lies to you

Sandboxed agents sit behind proxies that cut connections mid-stream. The CLI and MCP are built for that: screenshot downloads resume where they were cut (add --scale 0.5 on the CLI for a quarter-size transfer), reads retry, and when an input's response dies in transit the tool checks the device before reporting — you get landed, not landed, or an honest unknown (CLI exit code 2), never a bare failure for something that worked. Engine inputs are serialized per session, so a retry can't interleave with the original. Navigate by the hierarchy (tree / previewapk_hierarchy) — it is the most reliable channel there is — and use screenshots for visual proof.

Field reports — tell us what to build

You are one of the few who actually use this tool, and you use it for things we haven't imagined. Before you stop a session, file a field report: what broke, what worked, what you wish it had, and what you had to work around. One call — previewapk feedback --broke "..." --wish "..." or the previewapk_feedback tool. Reports are read and tallied by the team; the wishes of working agents are the roadmap.

REST API

Everything the CLI and MCP do is a plain HTTPS call with your key in the X-Api-Key header:

CallWhat it does
GET /portal/api/stateDevices, attached apps, links, session state
POST /portal/api/uploadMultipart: field apk, required field device (there is no default device — a call that doesn't name one fails). Replaces the device's app — on a running device (caller must hold the wheel) the new build is hot-swapped in live, no reboot
POST /portal/api/device/<id>/run{"driver":"agent"|"user"} — start the session
POST /portal/api/device/<id>/input{"action":"tap","x":.5,"y":.4} · swipe · key (Android keycode) · text
GET /portal/api/device/<id>/screenshotCurrent screen as PNG
GET /portal/api/device/<id>/hierarchyCurrent screen as a UI element tree (labels, bounds, state) — navigate by element, not pixels
POST /portal/api/device/<id>/handoff{"driver":"user"|"agent"} — switch who drives, mid-session
POST /portal/api/device/<id>/stopEnd the session

Driver modes

driver=agent — the API caller drives; you watch in the portal, with a Take Control button if you want the wheel. driver=user — you drive in the portal; API input is refused. Sessions auto-stop after 15 idle minutes; any input resets the timer.

The device model

One slot ($19/mo) = one device. Every run starts on a clean phone with exactly your build on it — pushing a different app replaces the previous one and nothing carries over — which keeps previews fast, honest, and free of interference from other apps.

Open your portal   Back to the homepage

Full documentation: getting started · API reference · CLI · MCP · CI recipes · Prompt library

Agent-readable version of this page: /llms.txt · Full text: /llms-full.txt · Agent skill: /skills/previewapk/SKILL.md · Setup: /setup.md · API spec: /openapi.yaml