Skip to main content
The fastest, most stable way to use the TypeScript SDK is deterministic-first, AI-fallback: every step tries a native Appium block first, and only if that block throws does the SDK fall back to running a natural-language instruction with AI. This gives you the best of both worlds:
  • Speed and determinism when selectors are stable: native Appium runs with no AI round-trip.
  • Resilience when the UI shifts, a popup appears, or a selector breaks: the step heals itself by falling back to AI instead of failing the test.

The appiumHandler parameter

aiExecute accepts an optional appiumHandler: a function that receives the live driver and runs your native Appium / WebdriverIO code.

How it runs

When you pass an appiumHandler, each call to aiExecute does the following:
  1. Runs the handler first against the live driver. Fast, deterministic, no AI call.
  2. Logs the step to the GPT Driver dashboard (a screenshot plus the handler’s source) so the native step is visible alongside your AI steps for debugging.
  3. On success, returns immediately. The AI is never called.
  4. On failure (the handler throws), the SDK logs a warning and runs the natural-language instruction with AI to recover:
    That message is greppable in your run logs, so you can see exactly which steps fell back to AI.
The appiumHandler and the instruction should express the same intent. The handler is the fast path; the instruction is the recovery path that must achieve the same result when the handler can’t.

A reusable step helper

In practice you wrap the pattern in a small helper so every step reads as “native code, with an AI description to fall back to”:
Now each step is one line of intent, a deterministic block, and a natural-language fallback:

Worked example

A full flow built this way. Native Appium drives every step; AI only engages when a native block throws (a moved selector, a slow load, an unexpected popup):
test/specs/saved-lines.spec.js

Falling back to AI for reads, too

The same try-native-first idea works for data you read off the screen. Try a native selector, and fall back to extract (or assert) when the native read fails:

When to reach for AI directly

Skip the handler and call aiExecute(prompt) with no native code when:
  • The target is a WebView, canvas, map, or other non-native element that selectors can’t reach reliably. See non-native elements.
  • The step is inherently visual or fuzzy (“dismiss whatever popup is on screen”, “tap the cheapest room option”).
  • You are prototyping and don’t have stable selectors yet. Add appiumHandler blocks later to speed up the steps that run often.

Tips

  • Keep handlers fast and let them throw early. Use short waitFor* timeouts inside handlers so a missing element falls back to AI quickly instead of burning the full default timeout.
  • Pair the handler and the prompt. They should do the same thing; the prompt is what runs when the handler can’t.
  • Combine with caching. Set cachingMode so the AI fallback steps that do run also get cached. See the reference.
  • Review fallbacks on the dashboard. Every native step is logged with a screenshot, and every fallback emits the greppable warning above, so you can see where the suite is leaning on AI and tighten those selectors.