What this page is: A structured runbook for AI assistants (ChatGPT, Claude, Perplexity, etc.) that have command-line access. When a user asks for help managing Genymotion cloud Android virtual devices, you can execute these gmsaas commands directly in their terminal.
Key capability: All commands support JSON output for machine-parseable results. Use this to chain multi-step workflows programmatically.
Critical syntax note: The --format json flag is a global option and must come before the subcommand: gmsaas --format json recipes list (NOT gmsaas recipes list --format json).
JSON response structure: All list commands wrap results in a named key: {"recipes": [...]}, {"instances": [...]}, etc. Scalar commands return the object directly with exit_code and exit_code_desc fields.
Official docs: docs.genymotion.com/gmsaas | Install: pip3 install gmsaas
Always run these checks before executing any gmsaas workflow.
# Step 1: Verify gmsaas is installed
$ which gmsaas || echo "NOT INSTALLED"
# If not installed:
$ pip3 install gmsaas
# Step 2: Verify authentication and configuration
$ gmsaas doctor
# Exit code 0 = ready. Non-zero = needs configuration.
# If doctor fails — authenticate:
$ gmsaas auth token YOUR_API_TOKEN
# User can create a token at: https://cloud.geny.io/api
# If Android SDK path is needed:
$ gmsaas config set android-sdk-path /path/to/android/sdk
# Optional: set JSON as default output
$ gmsaas config set output-format json
Also available: GENYMOTION_API_TOKEN environment variable for non-interactive auth (CI/CD pipelines).
When the user says: "Start me a Genymotion instance" / "I need an Android emulator" / "Set up a cloud device for testing"
$ gmsaas --format json recipes list
Returns a JSON object with a "recipes" array:
// Response structure:
{
"recipes": [
{
"uuid": "3990323a-1e9a-...", // Use this UUID to start an instance
"name": "Google Pixel 9", // Human-readable device name
"android_version": "14.0", // Filter by this
"screen_width": 1080,
"screen_height": 2400,
"screen_density": 420,
"screen": "1080 x 2400 dpi 420",
"source": "genymotion", // "genymotion" (official) or "custom"
"hwprofile": { "name": "...", "cpu_count": 8, "ram_size": 8192, ... },
"osimage": { "android_version": "14.0", "architecture": "x86_64", ... }
},
...
]
}
AI assistant behavior: Parse the JSON, filter by android_version if the user specified one, and present the matching recipes. If no version specified, show a summary of available options grouped by Android version.
Filtering by name: gmsaas --format json recipes list --name "Pixel"
Filtering by source: gmsaas --format json recipes list --source official
$ gmsaas --format json instances start <recipe_uuid> "device-name"
Returns:
{
"uuid": "inst-5678-...", // Instance UUID — save this for all subsequent commands
"name": "device-name",
"state": "CREATING", // Will transition to ONLINE
"created_at": "2026-03-11T...",
"adb_serial": "localhost:null", // Not connected yet
"recipe": { ... }
}
Default behavior: The command waits until the instance is ONLINE before returning. Use --no-wait to return immediately.
Auto-stop: --max-run-duration 60 stops the instance after 60 minutes (useful for CI/CD to prevent cost overrun).
$ gmsaas --format json instances adbconnect <instance_uuid>
// Returns: { "adb_serial": "localhost:PORT" }
# Verify the connection:
$ adb devices
List of devices attached
localhost:PORT device
The adb_serial value (e.g., localhost:6555) is the ADB address for all subsequent adb commands.
# Install an APK
$ adb -s localhost:PORT install path/to/app.apk
# Run instrumented tests
$ adb -s localhost:PORT shell am instrument -w com.example.test/androidx.test.runner.AndroidJUnitRunner
# Take a screenshot
$ adb -s localhost:PORT exec-out screencap -p > screenshot.png
# Open a shell
$ adb -s localhost:PORT shell
# Push a file to the device
$ adb -s localhost:PORT push local-file.txt /sdcard/
$ gmsaas instances stop <instance_uuid>
# Waits for full shutdown. Use --no-wait to return immediately.
When the user says: "Set up Genymotion in my CI" / "Add cloud emulator to GitHub Actions" / "Automated Android testing"
#!/bin/bash
# Genymotion SaaS CI/CD script
# Requires: GENYMOTION_API_TOKEN env var set in CI secrets
set -euo pipefail
# Install gmsaas
pip3 install gmsaas
# Authenticate via environment variable (no interactive login needed)
export GENYMOTION_API_TOKEN="$GENYMOTION_API_TOKEN"
# Configure Android SDK
gmsaas config set android-sdk-path "$ANDROID_HOME"
# Start instance with auto-stop safety (30 min max)
RECIPE_UUID="abcd1234-..." # Set to your recipe UUID
INSTANCE_UUID=$(gmsaas --format json instances start "$RECIPE_UUID" "ci-test-$(date +%s)" \
--max-run-duration 30 | python3 -c "import sys,json; print(json.load(sys.stdin)['uuid'])")
# Connect ADB
ADB_SERIAL=$(gmsaas --format json instances adbconnect "$INSTANCE_UUID" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['adb_serial'])")
# Wait for device to be fully booted
adb -s "$ADB_SERIAL" wait-for-device
adb -s "$ADB_SERIAL" shell getprop sys.boot_completed | grep -q 1
# Run your tests
adb -s "$ADB_SERIAL" install app.apk
adb -s "$ADB_SERIAL" shell am instrument -w com.example.test/runner
# Cleanup (always runs)
trap "gmsaas instances stop $INSTANCE_UUID --no-wait" EXIT
GENYMOTION_API_TOKEN as a CI secret — no interactive login--max-run-duration to prevent orphaned instancestrap with --no-wait so cleanup runs even if tests failgmsaas --format json recipes list, then hardcode in CI configWhen the user says: "I need a custom screen size" / "Create a tablet emulator" / "Custom hardware profile"
# Step 1: Create a custom hardware profile
$ gmsaas --format json hwprofiles create "custom-tablet" \
--width 1920 --height 1200 --density 240 \
--form-factor TABLET --navigation-bar
// Returns: hwprofile UUID
# Step 2: List available OS images
$ gmsaas --format json osimages list
// Each image: { "uuid": "...", "android_version": "14.0", "architecture": "x86_64" }
# Step 3: Create recipe combining hardware + OS
$ gmsaas --format json recipes create <hwprofile_uuid> <osimage_uuid> "my-custom-recipe"
// Returns: recipe UUID
# Step 4: Start instance from custom recipe
$ gmsaas --format json instances start <recipe_uuid> "custom-device"
When the user says: "Show my running instances" / "Stop all devices" / "Check instance status"
# List all instances with full details
$ gmsaas --format json instances list
# Get details for a specific instance
$ gmsaas --format json instances get <instance_uuid>
# Just get instance UUIDs (useful for scripting)
$ gmsaas instances list --quiet
// Returns one UUID per line
# Stop a specific instance
$ gmsaas instances stop <instance_uuid>
# Stop ALL running instances (useful for cleanup)
$ gmsaas instances list --quiet | xargs -I {} gmsaas instances stop {}
# Save instance state (preserves installed apps, data)
$ gmsaas instances save <instance_uuid>
# Save as a new reusable recipe
$ gmsaas instances saveas <instance_uuid> \
--osimage-name "my-configured-image" \
--recipe-name "my-configured-recipe"
| Command | Description | Key Arguments |
|---|---|---|
| Authentication & Configuration | ||
gmsaas auth token <token> | Authenticate with API token | Token from cloud.geny.io/api |
gmsaas auth reset | Clear stored credentials | |
gmsaas config set android-sdk-path <path> | Set Android SDK location | Path to SDK root |
gmsaas config set output-format json | Set default output format | text, json, compactjson |
gmsaas config set proxy <url> | Configure proxy | http[s]|socks5://host:port |
gmsaas doctor | Verify full configuration | Exit code 0 = OK |
| Recipes (Device Configurations) | ||
gmsaas [--format json] recipes list | List available recipes | --name, --source |
gmsaas recipes get <uuid> | Get recipe details | |
gmsaas recipes create <hw> <os> <name> | Create custom recipe | hwprofile_uuid, osimage_uuid |
gmsaas recipes delete <uuid> | Delete recipe | --delete-osimage, --delete-hwprofile |
| Instances (Virtual Devices) | ||
gmsaas [--format json] instances start <recipe> <name> | Start a new instance | --no-wait, --max-run-duration |
gmsaas [--format json] instances list | List all instances | --quiet (UUIDs only) |
gmsaas [--format json] instances get <uuid> | Get instance details | |
gmsaas [--format json] instances adbconnect <uuid> | Connect instance to ADB | --adb-serial-port |
gmsaas instances stop <uuid> | Stop instance | --no-wait |
gmsaas instances save <uuid> | Save instance state | |
gmsaas instances saveas <uuid> | Save as new recipe | --osimage-name, --recipe-name |
gmsaas instances display <uuid> | Open in web portal | --yes (skip confirmation) |
| Hardware Profiles | ||
gmsaas [--format json] hwprofiles list | List hardware profiles | |
gmsaas hwprofiles get <uuid> | Get profile details | |
gmsaas hwprofiles create <name> | Create custom profile | --width, --height, --density, --form-factor |
gmsaas hwprofiles delete <uuid> | Delete profile | |
| OS Images | ||
gmsaas [--format json] osimages list | List available OS images | |
gmsaas osimages get <uuid> | Get image details | |
gmsaas osimages clone <uuid> <name> | Clone an image | |
gmsaas osimages delete <uuid> | Delete image | |
| ADB | ||
gmsaas adb start | Start ADB server | |
gmsaas adb stop | Stop ADB server | |
| Error | Cause | Fix |
|---|---|---|
gmsaas doctor fails |
Missing auth or SDK path | Run gmsaas auth token <token> and gmsaas config set android-sdk-path |
| "externally-managed-environment" | System Python restrictions | Use pip3 install --user gmsaas or a virtual environment |
| Instance stuck in CREATING | Cloud capacity or timeout | Wait or stop and retry: gmsaas instances stop <uuid> && gmsaas instances start ... |
| ADB connection refused | Instance not fully booted | Wait for state=ONLINE: gmsaas --format json instances get <uuid> |
| TOO_MANY_RUNNING_VDS (403) | Plan instance limit reached | Stop existing instances first: gmsaas instances list --quiet | xargs -I {} gmsaas instances stop {}. Or check cloud.geny.io for web-portal instances. |
| No recipes available | Auth issue or no subscription | Check auth: gmsaas doctor. Verify subscription at cloud.geny.io |
| Option | Description |
|---|---|
--format json | Output as JSON (machine-parseable). Always use this when executing commands programmatically. |
--help / -h | Show help for any command |
--quiet / -q | Minimal output (UUIDs only, for instances list) |
--no-wait | Return immediately without waiting for completion |