@testrelic/appium-analytics
@testrelic/appium-analytics is a WebdriverIO service and reporter that adds comprehensive test analytics to your Appium mobile test suites — capturing device logs, Appium commands, network traffic, screenshots, and video, then generating interactive HTML reports and optionally uploading results to the TestRelic cloud platform.
What does this package include?
| Export | Import path | Description |
|---|---|---|
TestRelicService | @testrelic/appium-analytics/service | WDIO service — runs in the worker process alongside your live Appium session to collect data |
TestRelicReporter | @testrelic/appium-analytics | WDIO reporter — consumes collected data and writes JSON/HTML reports |
mergeReports() | @testrelic/appium-analytics/merge | Programmatic API to merge reports from multiple WDIO workers |
testrelic-appium | CLI binary | Merge, serve, and open reports from the terminal |
What does this package capture?
- Appium command tracking — every WebDriver command with timing, category, arguments, and return values; sensitive arguments are automatically redacted
- Device log capture — Android logcat and iOS syslog / crashlog streamed per test
- Network interception — HTTP requests and responses via Chrome DevTools Protocol (Android),
safariNetwork(iOS), or an automatic proxy fallback usingadb - Console log capture — webview / browser console output via BiDi
log.entryAddedor polling fallback - Screenshot collection — after every test, only on failure, or never
- Video recording — device screen recording using Appium recording commands or
adb screenrecord - Interactive HTML reports — self-contained timeline with commands, logs, network, screenshots, and video
- Cloud upload — batch or realtime upload to the TestRelic platform
Requirements
| Requirement | Version |
|---|---|
| Node.js | >= 18 (Appium 3.x requires >= 20.19) |
| WebdriverIO | >= 9.0.0 (peer dependency) |
@wdio/reporter | >= 9.0.0 (peer dependency) |
| Appium | 3.x (npm install -g appium@latest) |
| Android driver | UiAutomator2 (appium driver install uiautomator2) |
| iOS driver | XCUITest on macOS (appium driver install xcuitest) |
iOS testing requires macOS 13+ with Xcode 15+. iOS tests cannot run on Windows or Linux.
How do I install it?
- npm
- yarn
- pnpm
npm install @testrelic/appium-analytics
npm install --save-dev webdriverio @wdio/reporter
yarn add @testrelic/appium-analytics
yarn add --dev webdriverio @wdio/reporter
pnpm add @testrelic/appium-analytics
pnpm add --save-dev webdriverio @wdio/reporter
Quick Start
Add TestRelicService to services and TestRelicReporter to reporters in your WDIO config, then call TestRelicReporter.finalize() in onComplete:
import { join } from 'node:path';
import { TestRelicService } from '@testrelic/appium-analytics/service';
import { TestRelicReporter } from '@testrelic/appium-analytics';
const REPORT_DIR = join(process.cwd(), 'test-results');
async function onComplete() {
try {
await TestRelicReporter.finalize(process.cwd());
} catch (err) {
process.stderr.write(`[TestRelic] Cloud finalization failed: ${err}\n`);
}
}
export const config = {
runner: 'local',
port: 4723,
path: '/',
specs: ['./tests/**/*.test.ts'],
maxInstances: 1,
capabilities: [{
platformName: 'Android',
'appium:automationName': 'UiAutomator2',
'appium:deviceName': 'emulator-5554',
'appium:app': join(process.cwd(), 'apps', 'MyApp.apk'),
}],
framework: 'mocha',
mochaOpts: { ui: 'bdd', timeout: 60000 },
services: [
[TestRelicService, {
outputPath: REPORT_DIR,
includeDeviceLogs: true,
includeNetworkLogs: true,
screenshotOnEvery: 'failure',
}],
],
reporters: [
'spec',
[TestRelicReporter, {
outputPath: join(REPORT_DIR, 'report.json'),
htmlReportPath: join(REPORT_DIR, 'report.html'),
openReport: true,
}],
],
onComplete,
};
WDIO Integration
The package provides two WebdriverIO plugins that work together: a service and a reporter. Both accept the same AppiumReporterConfig options.
TestRelicService
Import path: @testrelic/appium-analytics/service
TestRelicService runs inside the worker process alongside your live Appium/WebDriver session. It registers the following hooks:
| Hook | What it does |
|---|---|
before | Detects platform and capabilities; starts DeviceLogCollector, ConsoleLogCollector, NetworkInterceptor, and prepares ScreenshotCollector |
after | Stops log and network collectors |
beforeTest / afterTest | Marks per-test log slice boundaries; captures screenshots; starts/stops video recording |
beforeCommand / afterCommand | Records every Appium command with timing and redacted arguments |
beforeAssertion / afterAssertion | Records WebdriverIO v9 assertion steps |
TestRelicReporter
Import path: @testrelic/appium-analytics
TestRelicReporter extends @wdio/reporter and runs in the worker process. It consumes data collected by TestRelicService and writes the final reports:
| Event | What it does |
|---|---|
onRunnerStart | Initializes the optional CloudClient |
onTestEnd | Pulls collected data from TestRelicService, builds a TimelineBuildInput, and optionally performs a realtime cloud upload |
onRunnerEnd | Builds the full timeline and summary, writes the JSON report, generates the HTML report, prints the console summary, and writes a cloud finalization manifest |
onComplete hook
TestRelicReporter.finalize() must be called from the WDIO launcher process (in onComplete) after all worker processes have exited. It reads the finalization manifest written by each worker and sends the final upload payload to the cloud.
async function onComplete() {
try {
await TestRelicReporter.finalize(process.cwd());
} catch (err) {
process.stderr.write(`[TestRelic] Cloud finalization failed: ${err}\n`);
}
}
export const config = {
// ...
onComplete,
};
When cloud upload is not configured, finalize() exits immediately if no manifest files are found — including it is always safe.
Platform Configuration
- Android
- iOS
import { join } from 'node:path';
import { TestRelicService } from '@testrelic/appium-analytics/service';
import { TestRelicReporter } from '@testrelic/appium-analytics';
const APP_PATH = join(process.cwd(), 'apps', 'MyApp.apk');
const REPORT_DIR = join(process.cwd(), 'test-results');
async function onComplete() {
try {
await TestRelicReporter.finalize(process.cwd());
} catch (err) {
process.stderr.write(`[TestRelic] Cloud finalization failed: ${err}\n`);
}
}
export const config = {
runner: 'local',
port: 4723,
path: '/',
specs: ['./tests/android/**/*.test.ts'],
maxInstances: 1,
capabilities: [{
platformName: 'Android',
'appium:automationName': 'UiAutomator2',
'appium:deviceName': 'emulator-5554',
'appium:app': APP_PATH,
'appium:autoGrantPermissions': true,
'appium:newCommandTimeout': 240,
'appium:appWaitActivity': '*',
'appium:noReset': false,
}],
logLevel: 'warn',
waitforTimeout: 15000,
connectionRetryTimeout: 120000,
connectionRetryCount: 3,
framework: 'mocha',
mochaOpts: { ui: 'bdd', timeout: 90000 },
services: [
[TestRelicService, {
outputPath: REPORT_DIR,
includeDeviceLogs: true,
includeNetworkLogs: true,
includeConsoleLogs: true,
includeCommands: true,
includeAssertions: true,
includeScreenshots: true,
screenshotOnEvery: 'failure',
includeVideoRecording: true,
}],
],
reporters: [
'spec',
[TestRelicReporter, {
outputPath: join(REPORT_DIR, 'report.json'),
htmlReportPath: join(REPORT_DIR, 'report.html'),
openReport: false,
}],
],
onComplete,
autoCompileOpts: {
tsNodeOpts: { project: './tsconfig.json' },
},
};
iOS testing requires macOS 13+ with Xcode 15+. These tests cannot run on Windows or Linux.
import { join } from 'node:path';
import { TestRelicService } from '@testrelic/appium-analytics/service';
import { TestRelicReporter } from '@testrelic/appium-analytics';
const APP_PATH = join(process.cwd(), 'apps', 'MyApp.app');
const REPORT_DIR = join(process.cwd(), 'test-results');
async function onComplete() {
try {
await TestRelicReporter.finalize(process.cwd());
} catch (err) {
process.stderr.write(`[TestRelic] Cloud finalization failed: ${err}\n`);
}
}
export const config = {
runner: 'local',
port: 4723,
path: '/',
specs: ['./tests/ios/**/*.test.ts'],
maxInstances: 1,
capabilities: [{
platformName: 'iOS',
'appium:automationName': 'XCUITest',
'appium:deviceName': 'iPhone 15',
'appium:platformVersion': '17.5',
'appium:app': APP_PATH,
'appium:newCommandTimeout': 240,
'appium:noReset': false,
}],
logLevel: 'warn',
waitforTimeout: 10000,
connectionRetryTimeout: 120000,
connectionRetryCount: 3,
framework: 'mocha',
mochaOpts: { ui: 'bdd', timeout: 60000 },
services: [
[TestRelicService, {
outputPath: REPORT_DIR,
includeDeviceLogs: true,
includeNetworkLogs: true,
includeConsoleLogs: true,
includeCommands: true,
includeAssertions: true,
includeScreenshots: true,
screenshotOnEvery: 'failure',
includeVideoRecording: false,
}],
],
reporters: [
'spec',
[TestRelicReporter, {
outputPath: join(REPORT_DIR, 'report.json'),
htmlReportPath: join(REPORT_DIR, 'report.html'),
openReport: false,
}],
],
onComplete,
autoCompileOpts: {
tsNodeOpts: { project: './tsconfig.json' },
},
};
Configuration Reference
Both TestRelicService and TestRelicReporter accept Partial<AppiumReporterConfig>. Options on TestRelicService control data collection; options on TestRelicReporter control report output and cloud upload. You can share the same options object between both plugins.
Core options
| Option | Type | Default | Description |
|---|---|---|---|
outputPath | string | './test-results/testrelic-timeline.json' | File path for the JSON report. Directories are created automatically. |
htmlReportPath | string | outputPath with .html extension | File path for the HTML report. |
openReport | boolean | true | Automatically open the HTML report in the browser after the run completes. |
includeDeviceLogs | boolean | true | Capture Android logcat / iOS syslog and crashlog entries. |
includeNetworkLogs | boolean | true | Capture HTTP network requests and responses. |
includeConsoleLogs | boolean | true | Capture webview and browser console output. |
includeScreenshots | boolean | true | Capture device screenshots. |
screenshotOnEvery | 'test' | 'failure' | 'never' | 'failure' | When to take screenshots: after every test, only on failure, or never. |
includeVideoRecording | boolean | false | Record the device screen for each test. |
includeCommands | boolean | true | Record every Appium / WebDriver command with timing and arguments. |
includeAssertions | boolean | true | Record WebdriverIO assertion steps (WDIO v9+). |
includeActionSteps | boolean | true | Capture named action steps within tests. |
deviceLogPollInterval | number (ms) | 1000 | Interval between device log polls. Minimum value is 100. |
preferBiDi | boolean | true | Use the WebDriver BiDi log.entryAdded event for console log capture when the driver supports it, falling back to polling otherwise. |
redactPatterns | (string | RegExp)[] | [] | Additional patterns appended to the built-in redaction set. Built-in patterns are always active. |
testRunId | string | Auto-generated UUID | Override the test run ID — useful for correlating with CI build numbers. |
reportMode | 'streaming' | 'batched' | 'streaming' | How the reporter writes the JSON file. Streaming reduces peak memory for large test suites. |
streamingThreshold | number | 0 | Minimum test count before streaming is active. 0 means always stream. |
quiet | boolean | false | Suppress the console summary table printed at the end of a run. |
metadata | Record<string, unknown> | null | Arbitrary key-value pairs attached to the test run report. Useful for build numbers, branch names, or environment tags. |
cloud | CloudReporterOptions | — | Cloud upload configuration. See Cloud options below. |
Cloud options
Passed as the cloud key inside the reporter options, or loaded automatically from .testrelic/testrelic-config.json and environment variables.
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | — | TestRelic API key. Required for cloud upload. |
endpoint | string | 'https://platform.testrelic.ai/api/v1' | TestRelic API endpoint. Override for self-hosted or staging environments. |
upload | 'batch' | 'realtime' | 'both' | 'batch' | Upload strategy. 'batch' uploads after onComplete; 'realtime' uploads as each test finishes; 'both' does both. |
timeout | number (ms) | 30000 | HTTP request timeout for cloud API calls. |
projectName | string | — | Override the project name shown in the TestRelic dashboard. Defaults to the git repository name. |
uploadArtifacts | boolean | true | Whether to upload screenshots and video files as run artifacts. |
artifactMaxSizeMb | number | 50 | Maximum size in MB for a single artifact file. Files exceeding this limit are skipped. |
queueMaxAge | number | 7 | Days to retain failed uploads in the local retry queue before discarding them. |
queueDirectory | string | System temp path | Directory where failed upload payloads are queued for retry on the next run. |
Platform Setup
- Android
- iOS
Prerequisites
- Node.js >= 20.19
- Java JDK 17+
- Windows 10/11, macOS, or Linux with hardware acceleration enabled
Step 1 — Install Android SDK Command-Line Tools
Download from developer.android.com/studio#command-line-tools-only, extract to a directory, and set environment variables:
- Windows (PowerShell)
- macOS / Linux
[System.Environment]::SetEnvironmentVariable("ANDROID_HOME", "C:\Android", "User")
[System.Environment]::SetEnvironmentVariable(
"Path",
"$env:Path;C:\Android\cmdline-tools\latest\bin;C:\Android\platform-tools;C:\Android\emulator",
"User"
)
export ANDROID_HOME=$HOME/Android
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator
Accept SDK licenses:
sdkmanager --licenses
Step 2 — Install platform tools, emulator, and system image
sdkmanager "platform-tools" "emulator"
sdkmanager "platforms;android-34"
sdkmanager "system-images;android-34;google_apis;x86_64"
Step 3 — Create an Android Virtual Device
avdmanager create avd -n MyEmulator -k "system-images;android-34;google_apis;x86_64" -d "pixel_7"
Step 4 — Start the emulator
emulator -avd MyEmulator -no-snapshot-load
Wait for the emulator to fully boot, then verify:
adb devices
# emulator-5554 device
Step 5 — Install Appium and UiAutomator2 driver
npm install -g appium@latest
appium driver install uiautomator2
Verify:
appium --version # 3.x.x
appium driver list --installed # uiautomator2
Step 6 — Start the Appium server
appium --address 127.0.0.1 --port 4723
iOS testing requires macOS 13+ with Xcode 15+. These tests cannot run on Windows or Linux.
Prerequisites
- macOS 13+ (Ventura or later recommended)
- Xcode 15+ with iOS Simulator
- Node.js >= 20.19
- Xcode Command Line Tools:
xcode-select --install
Step 1 — Install Appium and XCUITest driver
npm install -g appium@latest
appium driver install xcuitest
Verify:
appium driver list --installed # xcuitest
Step 2 — Boot an iOS simulator
xcrun simctl boot "iPhone 15"
open -a Simulator
List available simulators if iPhone 15 is not found:
xcrun simctl list devices
Step 3 — Start the Appium server
appium --address 127.0.0.1 --port 4723
Cloud Upload
Results can be uploaded to the TestRelic cloud platform. Cloud upload is optional — reports are always written locally regardless.
Config file
Create .testrelic/testrelic-config.json in your project root. The reporter discovers this file automatically:
{
"cloud": {
"apiKey": "<your-api-key>",
"endpoint": "https://platform.testrelic.ai/api/v1",
"upload": "batch"
}
}
Add .testrelic/testrelic-config.json to .gitignore to keep your API key out of version control. Use environment variables in CI/CD pipelines instead.
Environment variables
| Variable | Description |
|---|---|
TESTRELIC_API_KEY | TestRelic API key |
TESTRELIC_CLOUD_ENDPOINT | API endpoint URL |
TESTRELIC_UPLOAD_STRATEGY | Upload strategy: batch, realtime, or both |
Priority order
Configuration is merged in the following order — higher entries win:
TESTRELIC_API_KEY/TESTRELIC_CLOUD_ENDPOINT/TESTRELIC_UPLOAD_STRATEGYenvironment variablescloudinline options inside theTestRelicReporteroptions block inwdio.conf.ts.testrelic/testrelic-config.jsonconfig file
CLI
The package installs a testrelic-appium binary automatically.
Merge multiple report files (useful after parallel worker runs):
npx testrelic-appium merge \
./test-results/report-worker-1.json \
./test-results/report-worker-2.json \
-o ./test-results/merged-report.json
Serve a report directory (serves at http://127.0.0.1:9323 by default):
npx testrelic-appium serve ./test-results
npx testrelic-appium serve ./test-results --port 8080
Serve and open in browser (alias for serve + auto-open):
npx testrelic-appium open ./test-results
Merging Reports
When running tests across multiple WDIO workers, each worker writes its own JSON report. Use mergeReports() or the CLI merge command to combine them into a single timeline.
Programmatic merge:
import { mergeReports } from '@testrelic/appium-analytics/merge';
await mergeReports(
['./test-results/report-1.json', './test-results/report-2.json'],
{ output: './test-results/merged.json' }
);
CLI merge — see the CLI section above.
Redaction
The reporter automatically redacts sensitive data from command arguments and log entries using the following built-in patterns:
| Pattern | Matches |
|---|---|
| AWS-style access keys | 20-character alphanumeric strings starting with AKIA, ASIA, etc. |
| Bearer tokens | Values following Bearer in headers or strings |
| PEM private keys | -----BEGIN * PRIVATE KEY----- blocks |
| Embedded credentials | //user:password@ in URLs |
To add custom redaction patterns, use the redactPatterns option:
[TestRelicService, {
redactPatterns: [
/my-secret-\w+/, // regex pattern
'my-fixed-token-value', // literal string
],
}]
Custom patterns are appended to the built-in set — built-in patterns are always active.
Troubleshooting
Android: emulator won't start
- Enable Intel VT-x / AMD-V in BIOS settings
- On Windows 11: ensure the Hyper-V platform feature is enabled in Windows Features
- Try a cold boot:
emulator -avd MyEmulator -no-snapshot
Android: adb not found
- Ensure
$ANDROID_HOME/platform-toolsis on yourPATH - Run
adb kill-server && adb start-serverto reset the adb daemon
Android: Appium cannot find UiAutomator2
- Run
appium driver install uiautomator2again - If using a non-default Appium home, set
APPIUM_HOMEto point to the correct directory
Android: tests time out during session creation
- Ensure the emulator is fully booted before starting tests (
adb devicesshowsdevice, notoffline) - Increase
connectionRetryTimeoutin your WDIO config - Verify that the APK path in capabilities is correct and the file exists
iOS: xcrun: error: unable to find utility
- Run
sudo xcode-select --switch /Applications/Xcode.appto point to the correct Xcode installation
iOS: simulator not found
- Open Xcode > Settings > Platforms and download the required iOS Simulator runtime
- List available simulators:
xcrun simctl list devices
iOS: WebDriverAgent build fails
- Open
~/.appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent/WebDriverAgent.xcodeprojin Xcode - Set a valid signing team under Signing & Capabilities
Report not generated
- Ensure
TestRelicServiceis listed inservicesandTestRelicReporteris listed inreporters— both are required - Check that
outputPathdirectories are writable by the process