Automation API

Android device automation

Step Tracking & Debugging

Utils

Track automation progress and debug failures

Access step tracking through agent.utils.outOfSteps. Used for tracking automation progress and debugging when automations run out of steps or timeout.

OutOfStepsUtils Interface
TypeScript
interface OutOfStepsUtils {
storeScreen(
screen: AndroidNode,
stage: string,
screenState: string,
remainingSteps: number,
screenshotRecord: ScreenshotRecord
): Promise<void>;
submit(
type: "outOfSteps" | "timeout" | "debug",
tag?: string,
fromDisk?: boolean
): Promise<{ success: false; error: string } | { success: true; id: string }>;
enableDiskStorage(options?: {
maxBytes?: number
}): Promise<
{ success: false; error: string } |
{ success: true; directory: string; maxBytes: number }
>;
}

Stored screens are kept in sessionStorage, which only holds a few MB, so older screens are trimmed early. Call enableDiskStorage() to also keep them on disk, then pass fromDisk: true to submit to send the longer disk history.

storeScreen()

TypeScript
storeScreen(screen: AndroidNode, stage: string, screenState: string, remainingSteps: number, screenshotRecord: ScreenshotRecord): Promise<void>

Stores the current screen state for debugging purposes. Call this periodically during automation to track progress and help diagnose issues when automations fail.

Parameters

NameTypeDescription
screenAndroidNodeThe current screen content from screenContent()
stagestringCurrent stage/phase of the automation (e.g., 'login', 'checkout')
screenStatestringDescription of the current screen state
remainingStepsnumberNumber of steps remaining in the automation
screenshotRecordScreenshotRecordScreenshot quality setting

Examples

TypeScript
const screen = await agent.actions.screenContent();
// Store screen state for debugging
await agent.utils.outOfSteps.storeScreen(
screen,
"login",
"waiting_for_credentials",
50,
ScreenshotRecord.LOW_QUALITY
);

submit()

TypeScript
submit(type: "outOfSteps" | "timeout" | "debug", tag?: string, fromDisk?: boolean): Promise<{ success: false; error: string } | { success: true; id: string }>

Submits the collected screen states for analysis. Call this when the automation ends unexpectedly or for debugging. The server keeps the 200 most recent records per type per automation — except "debug" records, which are kept per tag: each tag retains its own 200 most recent records.

Parameters

NameTypeDescription
type"outOfSteps" | "timeout" | "debug"Reason for submission
tagstringOptional tag for "debug" submissions (defaults to "default", max 64 characters). Use distinct tags to keep separate debug histories — the server retains 200 debug records per tag. Ignored for non-debug submissions.
fromDisk?booleanWhen true, sends the screens stored on disk instead of the ones in sessionStorage. Returns an error if enableDiskStorage() hasn't been called. Pass undefined as the tag for a non-debug submission.(default: false)

Returns

{ success: true; id: string } | { success: false; error: string }Result with submission ID on success or error message on failure

Examples

Submit on timeout
TypeScript
const result = await agent.utils.outOfSteps.submit("timeout");
if (result.success) {
console.log("Debug data submitted with ID:", result.id);
} else {
console.log("Failed to submit:", result.error);
}
Submit for debugging
TypeScript
// Collect screens during automation
await agent.utils.outOfSteps.storeScreen(screen1, "step1", "initial", 100, ScreenshotRecord.HIGH_QUALITY);
await agent.utils.outOfSteps.storeScreen(screen2, "step2", "processing", 80, ScreenshotRecord.LOW_QUALITY);
// Submit for analysis (stored under the "default" tag)
await agent.utils.outOfSteps.submit("debug");
Submit debug data with a tag
TypeScript
// Each tag keeps its own history of 200 records,
// so tagged submissions don't push out other debug data
await agent.utils.outOfSteps.submit("debug", "login-flow");
Submit the disk history
TypeScript
// Needs enableDiskStorage() earlier in the run
await agent.utils.outOfSteps.submit("outOfSteps", undefined, true);

enableDiskStorage()

TypeScript
enableDiskStorage(options?: { maxBytes?: number }): Promise<{ success: false; error: string } | { success: true; directory: string; maxBytes: number }>

Also stores screens (UI hierarchy and screenshot) on disk, which keeps a much longer history than sessionStorage. Screens are still stored in sessionStorage as before, and submit sends that copy unless you pass fromDisk: true. Call it once, before the first storeScreen; screens stored before the call are only in sessionStorage. Each screen is gzipped and encrypted with AES-GCM, using a key that only exists in memory for the current run, and written as a hidden file in the device's Downloads folder. The oldest disk screens are trimmed when they exceed maxBytes, or when a write fails because the disk is full; a screen that can't be written to disk is only in sessionStorage. Screens are kept after submit, so later submissions still include them. The run's disk screens are deleted once agent.utils.job.submitTask succeeds with finish set to true (the default), whatever the status, so call outOfSteps.submit(type, tag, true) before that. Stored files older than one day, for example ones left by a run that crashed, are deleted when an automation starts. Calling it again only updates maxBytes. Needs app version 2.138 (150) or newer.

Parameters

NameTypeDescription
options.maxBytes?numberBudget for stored screens, measured as the size of their JSON. Values are clamped to 1–90 MB; 90 MB is also the most one submission sends.(default: 94371840 (90 MB))

Returns

{ success: true; directory: string; maxBytes: number } | { success: false; error: string }The directory used and the effective budget, or why disk storage could not be enabled (screens then stay in sessionStorage)

Examples

Enable at the start of the automation
TypeScript
const storage = await agent.utils.outOfSteps.enableDiskStorage();
if (!storage.success) {
console.warn("Disk storage unavailable:", storage.error);
}
// storeScreen is used exactly as before; screens go to sessionStorage and disk
await agent.utils.outOfSteps.storeScreen(screen, "login", "form", 50, ScreenshotRecord.HIGH_QUALITY);
// Send the disk history (falls back to sessionStorage if disk storage is off)
await agent.utils.outOfSteps.submit("outOfSteps", undefined, storage.success);
Use a smaller budget
TypeScript
await agent.utils.outOfSteps.enableDiskStorage({ maxBytes: 30 * 1024 * 1024 });

Supporting Types

ScreenshotRecord

Enum for screenshot quality settings.

TypeScript
enum ScreenshotRecord {
HIGH_QUALITY, // Full quality screenshot
LOW_QUALITY, // Compressed screenshot (faster, smaller)
NONE // No screenshot
}

Usage Pattern

Complete Debugging Flow
TypeScript
async function runAutomation() {
let remainingSteps = 100;
while (remainingSteps > 0) {
const screen = await agent.actions.screenContent();
// Store screen state periodically
await agent.utils.outOfSteps.storeScreen(
screen,
getCurrentStage(),
describeScreen(screen),
remainingSteps,
ScreenshotRecord.LOW_QUALITY
);
// Perform automation step
const result = await performStep(screen);
if (!result.success) {
// Submit debug data on failure
await agent.utils.outOfSteps.submit("outOfSteps");
throw new Error("Automation failed");
}
remainingSteps--;
}
// Submit on timeout if loop exits without success
await agent.utils.outOfSteps.submit("timeout");
}