Documentation Index Fetch the complete documentation index at: https://docs.morphllm.com/llms.txt
Use this file to discover all available pages before exploring further.
Beta Feature — Mobile automation is currently in beta. Please report any issues to founders@morphllm.com .
Mobile app testing is available on Pro and Scale plans. Upgrade your plan to get started.
Test your mobile apps with natural language. Describe what to test and Morph runs it on real iOS and Android devices.
Quick Start
import { MobileClient } from '@morphllm/morphsdk/tools/mobile' ;
const mobile = new MobileClient ({ apiKey: process . env . MORPH_API_KEY });
const result = await mobile . execute ({
task: "Tap the login button and verify the login form appears" ,
app: "https://github.com/myorg/myapp/releases/download/v1.0/app.ipa" ,
platform: "ios" ,
device: "iPhone 16 Pro"
});
console . log ( result . success ? 'Passed' : 'Failed' );
console . log ( result . trace_url ); // GIF of the test execution
Providing Your App
Pass a publicly accessible URL to your .ipa (iOS) or .apk (Android) file. Morph downloads and provisions it automatically.
GitHub Releases (Recommended)
The simplest approach for most teams:
await mobile . execute ({
task: "Test the checkout flow" ,
app: "https://github.com/myorg/myapp/releases/download/v1.2.3/MyApp.ipa" ,
platform: "ios"
});
GitHub Actions Artifacts
Upload your build artifact and pass the download URL:
name : Mobile Tests
on : [ push ]
jobs :
build-and-test :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
- name : Build iOS App
run : |
# Your build command (Xcode, Fastlane, etc.)
xcodebuild -scheme MyApp -sdk iphoneos -configuration Release
- name : Upload to GitHub Release
id : upload
uses : softprops/action-gh-release@v1
with :
files : build/MyApp.ipa
tag_name : build-${{ github.run_number }}
env :
GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
- name : Run Mobile Tests
env :
MORPH_API_KEY : ${{ secrets.MORPH_API_KEY }}
run : |
curl -X POST https://api.morphllm.com/v1/mobile-task \
-H "Authorization: Bearer $MORPH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"task": "Test the login flow with test@example.com and password123",
"app": "${{ steps.upload.outputs.assets[0].browser_download_url }}",
"platform": "ios",
"device": "iPhone 16 Pro",
"external_id": "PR-${{ github.event.pull_request.number }}",
"commit_id": "${{ github.sha }}"
}'
S3 or Cloud Storage
Generate a presigned URL and pass it:
import { S3Client , GetObjectCommand } from '@aws-sdk/client-s3' ;
import { getSignedUrl } from '@aws-sdk/s3-request-presigner' ;
const s3 = new S3Client ({ region: 'us-east-1' });
const command = new GetObjectCommand ({ Bucket: 'my-builds' , Key: 'app.ipa' });
const appUrl = await getSignedUrl ( s3 , command , { expiresIn: 3600 });
await mobile . execute ({
task: "Verify onboarding flow" ,
app: appUrl ,
platform: "ios"
});
Fastlane Integration
After building with Fastlane, upload to a release:
# Fastfile
lane :test do
build_app ( scheme: "MyApp" )
# Upload to GitHub Release
set_github_release (
repository_name: "myorg/myapp" ,
tag_name: "v #{ get_version_number } " ,
upload_assets: [ "MyApp.ipa" ]
)
end
API
execute()
Run a test synchronously:
const result = await mobile . execute ({
// Required
task: "Test the checkout flow" ,
app: "https://github.com/myorg/myapp/releases/download/v1.0/app.ipa" ,
// Optional
platform: "ios" , // "ios" | "android" (default: "ios")
device: "iPhone 16 Pro" , // Device name (default: "iPhone 16 Pro")
os_version: "18" , // OS version (auto-detected if omitted)
max_steps: 50 , // Max agent steps (default: 50)
record_trace: true , // Generate GIF trace (default: true)
// CI/CD tracking
external_id: "PR-123" ,
repo_id: "myorg/myapp" ,
commit_id: "abc123"
});
Response:
{
success : boolean ,
result ?: string , // Test findings
error ?: string , // Error if failed
task_id ?: string ,
steps_taken ?: number ,
execution_time_ms ?: number ,
trace_url ?: string , // GIF trace URL
trace_status ?: "PENDING" | "PROCESSING" | "COMPLETED" | "ERROR"
}
createTask()
Run tests asynchronously:
const task = await mobile . createTask ({
task: "Complete the onboarding flow" ,
app: "https://github.com/myorg/myapp/releases/download/v1.0/app.ipa" ,
device: "iPhone 16 Pro"
});
console . log ( 'Task started:' , task . task_id );
// Poll for completion
const result = await task . complete ();
console . log ( 'Result:' , result . result );
listDevices()
Get available devices:
const { devices } = await mobile . listDevices ();
devices . forEach ( d => {
console . log ( ` ${ d . device_name } ( ${ d . platform } )` );
});
Available Devices
iOS
Device Default OS iPhone 17 Pro Max 26 iPhone 17 Pro 26 iPhone 17 26 iPhone 16 Pro Max 18 iPhone 16 Pro 18 iPhone 15 Pro Max 17 iPad Pro 13 2025 26
Android
Device Default OS Samsung Galaxy S24 14 Samsung Galaxy S23 14 Google Pixel 8 14 Google Pixel 7 13
Writing Good Tasks
Be specific:
// Good
"Tap the login button, enter test@example.com in email, enter password123, and tap Sign In"
// Bad
"test login"
max_steps guide:
Simple tasks (tap, verify): 10-20 steps
Form submissions: 20-30 steps
Complex flows (checkout, onboarding): 30-50 steps
GIF Traces
Every test generates a GIF trace showing what happened:
const result = await mobile . execute ({
task: "Navigate through settings" ,
app: "https://..." ,
record_trace: true
});
if ( result . trace_url ) {
console . log ( 'Watch the test:' , result . trace_url );
}
FAQ
What devices are supported?
Real iOS devices (iPhone 15-17, iPad Pro) and Android devices (Samsung Galaxy, Google Pixel). Use listDevices() to see all available options.
What URL formats work for the app parameter?
Simple tests: 30-60 seconds
Medium tests: 1-2 minutes
Complex flows: 2-5 minutes
What AI model powers the testing?
Morph uses Gemini 3 Flash for understanding your app’s UI and executing actions. The model analyzes screenshots, identifies elements, and performs taps, swipes, and text input.
Can I test apps not yet published to the App Store?
Yes. Provide a URL to your development build (.ipa for iOS, .apk for Android). This is ideal for testing PR builds before merging.