Duoplus Dashboard
Local web UI that talks to the Duoplus OpenAPI to list cloud phones, power them on/off, and orchestrate warmup runs (power on → run imported workflow → power off).
Setup
cd dashboard
cp .env.example .env
# edit .env and paste your API key into DUOPLUS_API_KEY
bun install
bun run dev
Enabling the API key
If every request fails with code: 160002 (permission denied), API access
is disabled on your key. Fix:
- Log into the Duoplus console.
- Go to Team Management → API (or equivalent).
- Enable API access on the key, or scope it to the operations the dashboard
uses:
/cloudphone/list,/cloudphone/status,/cloudphone/details/cloudphone/batch-power-on,/cloudphone/batch-power-off/cloudphone/batch-restart/cloudphone/adb-whitelist,/cloudphone/batch-enable-adb/automation/custom-templates,/automation/loop-task-create,/automation/loop-task-list
The error message from the UI will include the Duoplus code — anything
that's not 200 is an API-side error. 160002 specifically = API disabled
on your team/key.
Endpoints the UI exposes
| Method | Path | Purpose |
|---|---|---|
| GET | / |
Serves the HTML frontend |
| GET | /api/devices |
Proxies /cloudphone/list |
| POST | /api/status |
Proxies /cloudphone/status; body {ids: []} |
| POST | /api/power-on |
Proxies /cloudphone/batch-power-on |
| POST | /api/power-off |
Proxies /cloudphone/batch-power-off |
| POST | /api/restart |
Proxies /cloudphone/batch-restart |
| POST | /api/run-warmup |
Starts an orchestrated run; body {device_id, template_name?, template_id?} |
| GET | /api/run/:id/logs |
Poll progress of a running orchestration |
| GET | /api/templates |
List the imported custom templates |
Orchestrator flow
When you click Run Warmup on a device, the server:
batch-power-onfor that device ID- Polls
/cloudphone/statusevery 5s until status includesonline/running/active(max 3 min) - If a template name is configured, resolves it to an ID via
/automation/custom-templates /automation/loop-task-create→ returns task ID- Polls
/automation/loop-task-listevery 15s until the task status isfinished/completed/done/stopped, or 20 min cap batch-power-off
If any step errors mid-flight, the orchestrator still attempts a safety power-off so the device doesn't sit on indefinitely.
Security
.envis not committed — keep the key out of git.- Never paste the key into shared chats (rotate it if you do).
- The dashboard has no auth — bind to
localhostonly. If you expose it remotely, put it behind a reverse proxy with auth (Caddy basic auth, Tailscale, etc.). - Duoplus caps each endpoint to 1 QPS. The UI respects this by debouncing clicks; if you trigger a bulk action on many devices, the server serializes them one second apart.
Next steps
- Wire an IP-whitelist form (calls
/cloudphone/adb-whitelist) so you can update whitelists for the fleet in bulk when your residential IP rotates. - Add a Schedule Warmup button that creates a
scheduled-taskvia/automation/scheduled-task-createfor a recurring nightly run. - Fleet-wide template management: sync the generated workflow JSON into Duoplus as a custom template via their import endpoint (docs don't publish this — may need manual import via Duoplus web console).