Skip to main content

Debugging Tools

PhoneClaw provides several tools and techniques to help you debug your automation scripts and understand what’s happening during execution.

Using speakText for Debugging

The speakText() function is your primary debugging tool. It provides audio feedback about script execution and can help you understand where your automation is succeeding or failing.

Basic Debug Output

speakText("Starting automation");

await magicClicker("Login button");
speakText("Clicked login button");

await delay(2000);
speakText("Waiting for page to load");

const result = await magicScraper("Error message on screen");
speakText("Scraper result: " + result);

Variable Inspection

const username = "testuser@example.com";
speakText("Username is: " + username);

const attempts = 3;
speakText("Retry attempts: " + attempts);

const isLoggedIn = true;
speakText("Login status: " + (isLoggedIn ? "success" : "failed"));

Checkpoint Debugging

function checkpoint(message) {
  speakText("Checkpoint: " + message);
}

checkpoint("Starting workflow");
await magicClicker("Menu");

checkpoint("Menu opened");
await magicClicker("Settings");

checkpoint("Settings opened");
await magicClicker("Account");

checkpoint("Workflow completed");

Error Handling

Try-Catch Blocks

Wrap potentially failing operations in try-catch blocks to gracefully handle errors:
try {
  await magicClicker("Submit button");
  speakText("Button clicked successfully");
} catch (error) {
  speakText("Error clicking button: " + error);
  // Fallback logic
}

Comprehensive Error Handling

async function safeClick(elementDescription, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      speakText("Attempt " + (i + 1) + " to click: " + elementDescription);
      await magicClicker(elementDescription);
      speakText("Success!");
      return true;
    } catch (error) {
      speakText("Attempt failed: " + error);
      if (i < maxRetries - 1) {
        await delay(2000);
      }
    }
  }
  speakText("All attempts failed for: " + elementDescription);
  return false;
}

// Usage
const success = await safeClick("Login button");
if (!success) {
  speakText("Stopping automation due to error");
  return;
}

Debugging magicClicker

Test Element Visibility

Before using magicClicker, verify the element is visible:
// First, try to read information about the element
const elementInfo = await magicScraper("Is there a blue login button visible?");
speakText("Element check: " + elementInfo);

// If confirmed visible, proceed with click
if (elementInfo.includes("yes") || elementInfo.includes("visible")) {
  await magicClicker("blue login button");
} else {
  speakText("Element not found, checking alternative");
  await magicClicker("sign in button");
}

Progressive Description Refinement

// Start broad, get more specific if needed
const descriptions = [
  "submit button",
  "blue submit button",
  "blue submit button at bottom",
  "blue rectangular submit button at bottom right"
];

for (const desc of descriptions) {
  try {
    speakText("Trying: " + desc);
    await magicClicker(desc);
    speakText("Success with: " + desc);
    break;
  } catch (error) {
    speakText("Failed with: " + desc);
  }
}

Add Delays for UI Loading

// Bad: No delay, UI might not be ready
await magicClicker("Next button");
await magicClicker("Submit button"); // Might fail

// Good: Allow time for UI to load
await magicClicker("Next button");
speakText("Waiting for next page");
await delay(2000);
await magicClicker("Submit button"); // More likely to succeed

Debugging magicScraper

Verify Scraped Content

const scrapedText = await magicScraper("The verification code displayed");
speakText("Scraped text: " + scrapedText);

// Check if result is valid
if (!scrapedText || scrapedText === "null" || scrapedText === "undefined") {
  speakText("Warning: No text scraped, retrying");
  await delay(1000);
  scrapedText = await magicScraper("The verification code displayed");
}

Validate Scraped Data

// Scrape and validate format
const otpCode = await magicScraper("The 6-digit verification code");
speakText("Scraped OTP: " + otpCode);

// Validate it's actually 6 digits
if (otpCode && /^\d{6}$/.test(otpCode)) {
  speakText("Valid OTP code found");
} else {
  speakText("Invalid OTP format, expected 6 digits");
  // Handle error
}

Question Refinement

// Vague question
const result1 = await magicScraper("What's the code?"); // Might fail

// Specific question
const result2 = await magicScraper("What is the 6-digit verification code shown in the SMS message?"); // Better

speakText("Vague result: " + result1);
speakText("Specific result: " + result2);

Debugging Scheduled Tasks

Verify Schedule Creation

const cronExpr = "0 */2 * * *"; // Every 2 hours
speakText("Creating schedule with expression: " + cronExpr);

try {
  schedule("myAutomation", cronExpr);
  speakText("Schedule created successfully");
} catch (error) {
  speakText("Failed to create schedule: " + error);
}

Test Schedule Timing

Start with a short interval for testing:
// For testing: Run every 2 minutes
const testSchedule = "*/2 * * * *";
speakText("Test schedule: every 2 minutes");
schedule("test", testSchedule);

// After testing: Switch to production schedule
// const prodSchedule = "0 9 * * *"; // Daily at 9 AM

Debugging Scheduled Script

Add timestamp logging:
function getTimestamp() {
  return new Date().toISOString();
}

speakText("Scheduled task started at: " + getTimestamp());

try {
  // Your automation logic
  await magicClicker("Refresh button");
  speakText("Task completed at: " + getTimestamp());
} catch (error) {
  speakText("Task failed at: " + getTimestamp() + ", Error: " + error);
}

Common Debugging Patterns

State Machine Debugging

const states = {
  START: "start",
  LOGGED_IN: "logged_in",
  FORM_FILLED: "form_filled",
  SUBMITTED: "submitted",
  COMPLETE: "complete"
};

let currentState = states.START;

function setState(newState) {
  speakText("State change: " + currentState + " to " + newState);
  currentState = newState;
}

setState(states.START);
await magicClicker("Login");
setState(states.LOGGED_IN);

await magicClicker("Form field");
setState(states.FORM_FILLED);

await magicClicker("Submit");
setState(states.SUBMITTED);

speakText("Final state: " + currentState);

Conditional Debugging

const DEBUG = true; // Set to false to disable debug output

function debug(message) {
  if (DEBUG) {
    speakText("[DEBUG] " + message);
  }
}

debug("Starting automation");
await magicClicker("Button");
debug("Button clicked");
await delay(1000);
debug("Delay complete");

Performance Timing

let startTime = Date.now();

function logTime(label) {
  const elapsed = Date.now() - startTime;
  speakText(label + ": " + elapsed + " milliseconds");
}

logTime("Start");
await magicClicker("Button1");
logTime("After button 1");

await delay(2000);
logTime("After delay");

await magicClicker("Button2");
logTime("After button 2");

logTime("Total time");

Testing Strategies

Incremental Testing

1

Test Single Action

Start by testing just one action:
await magicClicker("Login button");
speakText("Single action test complete");
2

Add Second Action

Once first action works, add the next:
await magicClicker("Login button");
await delay(2000);
await magicClicker("Email field");
speakText("Two actions test complete");
3

Build Complete Flow

Continue adding actions one at a time until the full automation works.

Isolation Testing

Test problematic sections in isolation:
// Comment out everything except the problem section

// speakText("Starting full automation");
// await magicClicker("Menu");
// await delay(1000);

// Test just the problematic part
speakText("Testing problem section");
const result = await magicScraper("Error message text");
speakText("Result: " + result);

// await magicClicker("Submit");
// speakText("Complete");

Android Debug Bridge (ADB)

For advanced debugging, use ADB to view system logs:

View Logcat Output

# View all PhoneClaw logs
adb logcat | grep PhoneClaw

# Filter for errors only
adb logcat *:E | grep PhoneClaw

# Save logs to file
adb logcat -d > phoneclaw_logs.txt

Clear Logs and Reproduce

# Clear existing logs
adb logcat -c

# Run your automation in PhoneClaw

# View new logs
adb logcat -d > debug_logs.txt

Best Practices

Start Simple

Begin with simple automations and add complexity gradually.

Add Logging

Use speakText liberally to track execution flow and variable values.

Handle Errors

Wrap risky operations in try-catch blocks with fallback logic.

Test Incrementally

Test each new addition before moving to the next step.

Use Delays

Add sufficient delays for UI loading and transitions.

Be Specific

Use detailed descriptions for magicClicker and magicScraper.

Getting Help

If you’re still stuck after debugging:

Common Issues

Check if your issue is already documented

FAQ

Review frequently asked questions

Discord Community

Ask for help from experienced users

GitHub Issues

Report bugs with your debug logs