Skip to main content
Ask AI

@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?

ExportImport pathDescription
TestRelicService@testrelic/appium-analytics/serviceWDIO service — runs in the worker process alongside your live Appium session to collect data
TestRelicReporter@testrelic/appium-analyticsWDIO reporter — consumes collected data and writes JSON/HTML reports
mergeReports()@testrelic/appium-analytics/mergeProgrammatic API to merge reports from multiple WDIO workers
testrelic-appiumCLI binaryMerge, 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 using adb
  • Console log capture — webview / browser console output via BiDi log.entryAdded or 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

RequirementVersion
Node.js>= 18 (Appium 3.x requires >= 20.19)
WebdriverIO>= 9.0.0 (peer dependency)
@wdio/reporter>= 9.0.0 (peer dependency)
Appium3.x (npm install -g appium@latest)
Android driverUiAutomator2 (appium driver install uiautomator2)
iOS driverXCUITest on macOS (appium driver install xcuitest)
note

iOS testing requires macOS 13+ with Xcode 15+. iOS tests cannot run on Windows or Linux.


How do I install it?

Install the package and peer dependencies
npm install @testrelic/appium-analytics
npm install --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:

wdio.conf.ts
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:

HookWhat it does
beforeDetects platform and capabilities; starts DeviceLogCollector, ConsoleLogCollector, NetworkInterceptor, and prepares ScreenshotCollector
afterStops log and network collectors
beforeTest / afterTestMarks per-test log slice boundaries; captures screenshots; starts/stops video recording
beforeCommand / afterCommandRecords every Appium command with timing and redacted arguments
beforeAssertion / afterAssertionRecords 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:

EventWhat it does
onRunnerStartInitializes the optional CloudClient
onTestEndPulls collected data from TestRelicService, builds a TimelineBuildInput, and optionally performs a realtime cloud upload
onRunnerEndBuilds 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

Required for cloud upload

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.

wdio.conf.ts
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

wdio.android.conf.ts
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' },
},
};

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

OptionTypeDefaultDescription
outputPathstring'./test-results/testrelic-timeline.json'File path for the JSON report. Directories are created automatically.
htmlReportPathstringoutputPath with .html extensionFile path for the HTML report.
openReportbooleantrueAutomatically open the HTML report in the browser after the run completes.
includeDeviceLogsbooleantrueCapture Android logcat / iOS syslog and crashlog entries.
includeNetworkLogsbooleantrueCapture HTTP network requests and responses.
includeConsoleLogsbooleantrueCapture webview and browser console output.
includeScreenshotsbooleantrueCapture device screenshots.
screenshotOnEvery'test' | 'failure' | 'never''failure'When to take screenshots: after every test, only on failure, or never.
includeVideoRecordingbooleanfalseRecord the device screen for each test.
includeCommandsbooleantrueRecord every Appium / WebDriver command with timing and arguments.
includeAssertionsbooleantrueRecord WebdriverIO assertion steps (WDIO v9+).
includeActionStepsbooleantrueCapture named action steps within tests.
deviceLogPollIntervalnumber (ms)1000Interval between device log polls. Minimum value is 100.
preferBiDibooleantrueUse 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.
testRunIdstringAuto-generated UUIDOverride 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.
streamingThresholdnumber0Minimum test count before streaming is active. 0 means always stream.
quietbooleanfalseSuppress the console summary table printed at the end of a run.
metadataRecord<string, unknown>nullArbitrary key-value pairs attached to the test run report. Useful for build numbers, branch names, or environment tags.
cloudCloudReporterOptionsCloud 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.

OptionTypeDefaultDescription
apiKeystringTestRelic API key. Required for cloud upload.
endpointstring'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.
timeoutnumber (ms)30000HTTP request timeout for cloud API calls.
projectNamestringOverride the project name shown in the TestRelic dashboard. Defaults to the git repository name.
uploadArtifactsbooleantrueWhether to upload screenshots and video files as run artifacts.
artifactMaxSizeMbnumber50Maximum size in MB for a single artifact file. Files exceeding this limit are skipped.
queueMaxAgenumber7Days to retain failed uploads in the local retry queue before discarding them.
queueDirectorystringSystem temp pathDirectory where failed upload payloads are queued for retry on the next run.

Platform Setup

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:

[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"
)

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

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:

.testrelic/testrelic-config.json
{
"cloud": {
"apiKey": "<your-api-key>",
"endpoint": "https://platform.testrelic.ai/api/v1",
"upload": "batch"
}
}
tip

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

VariableDescription
TESTRELIC_API_KEYTestRelic API key
TESTRELIC_CLOUD_ENDPOINTAPI endpoint URL
TESTRELIC_UPLOAD_STRATEGYUpload strategy: batch, realtime, or both

Priority order

Configuration is merged in the following order — higher entries win:

  1. TESTRELIC_API_KEY / TESTRELIC_CLOUD_ENDPOINT / TESTRELIC_UPLOAD_STRATEGY environment variables
  2. cloud inline options inside the TestRelicReporter options block in wdio.conf.ts
  3. .testrelic/testrelic-config.json config 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:

PatternMatches
AWS-style access keys20-character alphanumeric strings starting with AKIA, ASIA, etc.
Bearer tokensValues 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-tools is on your PATH
  • Run adb kill-server && adb start-server to reset the adb daemon

Android: Appium cannot find UiAutomator2

  • Run appium driver install uiautomator2 again
  • If using a non-default Appium home, set APPIUM_HOME to point to the correct directory

Android: tests time out during session creation

  • Ensure the emulator is fully booted before starting tests (adb devices shows device, not offline)
  • Increase connectionRetryTimeout in 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.app to 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.xcodeproj in Xcode
  • Set a valid signing team under Signing & Capabilities

Report not generated

  • Ensure TestRelicService is listed in services and TestRelicReporter is listed in reporters — both are required
  • Check that outputPath directories are writable by the process
Loading chart…