API server for droidrun - automate your Android phone using LLMs (Claude, ChatGPT, Gemini, DeepSeek, Ollama). Just describe what you want done.
- Enable Developer Options: Settings > About Phone > Tap "Build Number" 7 times
- Enable USB Debugging: Settings > Developer Options > USB Debugging
- Connect phone via USB
- When prompted, tap "Allow" to authorize your computer
Get a key from one of the supported providers:
- Google AI Studio - Gemini (recommended)
- Anthropic - Claude
- OpenAI - ChatGPT / GPT-4
- DeepSeek - DeepSeek
- Ollama - Local models (no API key needed)
# 1. Start the server
docker run -d --name droidrun \
--privileged \
--network=host \
-v /dev/bus/usb:/dev/bus/usb \
-v ~/.android:/root/.android \
-e DROIDRUN_SERVER_KEY="change-me" \
ghcr.io/8ff/droidrunnerd:latest
# 2. Verify it's running
curl http://localhost:8000/healthMac users: Replace
--network=hostwith-p 8000:8000. See Wireless ADB below.
Docker on Mac doesn't support USB passthrough, so you'll need to connect to your phone over WiFi instead.
- Go to Settings > Developer Options > Wireless debugging
- Enable Wireless debugging
- Tap Pair device with pairing code - note the pairing code and IP:port
docker run -d --name droidrun \
--privileged \
-p 8000:8000 \
-v ~/.android:/root/.android \
-e DROIDRUN_SERVER_KEY="change-me" \
ghcr.io/8ff/droidrunnerd:latest# Pair (one-time) - use IP:port and code from Wireless debugging screen
docker exec -it droidrun adb pair 192.168.1.100:37123
# Enter pairing code when prompted
# Connect (use the main IP:port shown under "Wireless debugging", not the pairing port)
docker exec droidrun adb connect 192.168.1.100:5555
# Verify connection
docker exec droidrun adb devicesNote: The pairing port (e.g., 37123) and connect port (e.g., 5555) are different. Check the Wireless debugging screen for both.
# Download the client (or build: cd client && go build -o droidrun-client)
# Releases: https://github.com/8ff/droidrunnerd/releases
# Set credentials
export DROIDRUN_SERVER_KEY="change-me"
export LLM_API_KEY="your-api-key"
# Run a task (defaults to Google/Gemini)
./droidrun-client -server http://localhost:8000 -key $LLM_API_KEY "open settings"
# Specify provider and model
./droidrun-client -server http://localhost:8000 -key $LLM_API_KEY \
-provider Anthropic -model claude-sonnet-4-20250514 "open settings"
# Run a predefined task
./droidrun-client -server http://localhost:8000 -task tasks/whatsapp-reply.toml# Submit a task (defaults to Google/Gemini)
curl -X POST http://localhost:8000/run \
-H "Content-Type: application/json" \
-H "X-Server-Key: $DROIDRUN_SERVER_KEY" \
-H "X-API-Key: $LLM_API_KEY" \
-d '{"goal":"open WhatsApp and send hello to Mom"}'
# With specific provider/model
curl -X POST http://localhost:8000/run \
-H "Content-Type: application/json" \
-H "X-Server-Key: $DROIDRUN_SERVER_KEY" \
-H "X-API-Key: $LLM_API_KEY" \
-d '{"goal":"open WhatsApp", "provider":"Anthropic", "model":"claude-sonnet-4-20250514"}'
# Check task status
curl -H "X-Server-Key: $DROIDRUN_SERVER_KEY" http://localhost:8000/task/TASK_ID
# Cancel a task
curl -X DELETE -H "X-Server-Key: $DROIDRUN_SERVER_KEY" http://localhost:8000/task/TASK_IDBase URL: http://localhost:8000
Authentication: All endpoints except /health require the X-Server-Key header.
Submit a new task to the queue.
Headers:
Content-Type: application/json
X-Server-Key: your-server-key
X-API-Key: your-llm-api-key
Request:
{
"goal": "open WhatsApp and check unread messages",
"provider": "Google",
"model": "gemini-2.0-flash",
"max_steps": 30
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
goal |
string | Yes | - | What you want the agent to do |
provider |
string | No | Google |
LLM provider (see below) |
model |
string | No | auto | Model name |
max_steps |
int | No | 30 |
Maximum steps (1-100) |
Providers:
| Provider | Default Model |
|---|---|
Google |
gemini-2.0-flash |
Anthropic |
claude-sonnet-4-20250514 |
OpenAI |
gpt-4o |
DeepSeek |
deepseek-chat |
Ollama |
llama3.2 |
Response: 200 OK
{
"task_id": "a1b2c3d4",
"status": "queued",
"position": 0
}Get task status and result.
Headers:
X-Server-Key: your-server-key
Response: 200 OK
{
"id": "a1b2c3d4",
"status": "completed",
"success": true,
"result": "Found 3 unread messages in WhatsApp",
"error": "",
"logs": "...",
"steps": [...],
"request": {
"goal": "open WhatsApp and check unread messages",
"provider": "Google",
"model": "gemini-2.0-flash",
"max_steps": 30
},
"created_at": "2025-01-28T10:00:00Z",
"started_at": "2025-01-28T10:00:01Z",
"finished_at": "2025-01-28T10:00:15Z"
}| Field | Description |
|---|---|
status |
queued, running, completed, failed, cancelled |
success |
Whether the goal was achieved |
result |
Agent's final answer/summary |
error |
Error message if failed |
logs |
Execution logs |
steps |
Array of steps taken |
Cancel a queued or running task.
Headers:
X-Server-Key: your-server-key
Response: 200 OK
{
"status": "cancelled"
}Health check. No authentication required.
Response: 200 OK
{
"status": "ok",
"version": "1.0.0",
"queue_size": 0,
"current_task": ""
}All errors return JSON:
{
"error": "error message",
"request_id": "abc123"
}| Code | Description |
|---|---|
400 |
Bad request (invalid JSON, missing goal, etc.) |
401 |
Unauthorized (missing or invalid X-Server-Key) |
404 |
Task not found |
405 |
Method not allowed |
# Build container
docker build -t droidrun .
# Or build binaries directly
cd server && go build -o droidrun-server
cd client && go build -o droidrun-client| Variable | Description |
|---|---|
DROIDRUN_SERVER_KEY |
Required. Server authentication key |
GOOGLE_API_KEY |
Google AI API key |
ANTHROPIC_API_KEY |
Anthropic API key |
OPENAI_API_KEY |
OpenAI API key |
No device detected:
# Check ADB sees your phone
docker exec droidrun adb devices
# Should show your device, not "unauthorized""unauthorized" device:
- Check phone screen for USB debugging prompt
- Tap "Allow" and check "Always allow"
Container won't start:
- Ensure
DROIDRUN_SERVER_KEYis set (required)
This project is a wrapper around droidrun - the actual Android automation magic happens there. Check them out!
MIT