Links

Cross-document messages

Interact with the virtual device via a Javascript post-message API
Cross-document messaging, when enabled via the &xdocMsg=true query parameter, allows you to issue commands to the embedded iFrame via Javascript via postMessage(message, targetOrigin).
Messages without any parameters can be passed directly as strings, e.g.
postMessage('requestSession', '*')
Messages with parameters should be passed as objects with the message name in the type field. E.g.
postMessage({ type: 'mouseclick', x: 100, y:100 }, '*')

Sendable Messages

requestSession

Equivalent to clicking play
postMessage('requestSession', '*')

emitHomeButton

Taps the home button for iOS apps when available
postMessage('emitHomeButton', '*')

rotateLeft

Rotates counter-clockwise
postMessage('rotateLeft', '*')

rotateRight

Rotates clockwise
postMessage('rotateRight', '*')

setScale

Sets device scale to a value between 10 and 100
postMessage({ type: 'setScale', value: 50 })

saveScreenshot

Prompts user to download screenshot
postMessage('saveScreenshot', '*')

getScreenshot

Sends screenshot data directly to parent window. See the screenshot event the iFrame posts to the parent.
postMessage('getScreenshot', '*')

heartbeat

Sends heartbeat to prevent inactivity timeout
postMessage('heartbeat', '*')

mouseclick

Sends click event at the provided coordinates
postMessage({ type: 'mouseclick', x: 100, y:100 }, '*')

pasteText

Pastes the provided text
postMessage({ type: 'pasteText', value: 'Hello World' }, '*')

keypress

Sends keypress. key should be a string that identifies the key pressed, e.g. 'a'. Acceptable values on Android also include 'volumeUp' and 'volumeDown'.
postMessage({ type: 'keypress', key: 'a', shiftKey: true }, '*') // would send 'A"

language

Sets language, restarts app
postMessage({ type: 'language', value: 'fr' }, '*')

location

Sets location. value should be 2-length array that contains [latitude, longitude]
postMessage({ type: 'location', value: [50.0, -100.0] }, '*')

url

Opens deep-link or regular URL in Safari
postMessage({ type: 'url', value: 'https://appetize.io' }, '*')

shakeDevice

Send shake gesture to iOS apps
postMessage('shakeDevice', '*')

androidKeycodeMenu

Sends Android KEYCODE_MENU command
postMessage('androidKeycodeMenu', '*')

adbShellCommand

Executes an adb shell command on an Android device.
If a session is already running the command will be executed immediately. If the session has not been started, the command will execute upon start.
postMessage({
type: 'adbShellCommand',
value: 'am start -a android.intent.action.VIEW -d https://appetize.io/'
}, '*')

biometryMatch

(Android 8+ only) simulate a matching fingerprint
postMessage('biometryMatch', '*')

biometryNonMatch

(Android 8+ only) simulate a non-matching fingerprint
postMessage('biometryNonMatch', '*')

disableInteractions

Disables all user interactions
postMessage('disableInteractions', '*')

enableInteractions

Re-enables all user interactions
postMessage('enableInteractions', '*')

restartApp

Kills and restarts app in same session
postMessage('restartApp', '*')

endSession

Ends the session
postMessage('endSession', '*')

Receivable Messages

The iFrame also posts messages to the parent window via message event. You can listen for them with an event handler on the window:
window.addEventListener('message', (event) => {
const type = typeof event.data === 'string' ? event.data : event.data.type
console.log(type)
})

userInteractionReceived

Session has received an interaction from the user
{
data: {
type: "userInteractionReceived",
value: {
altKey: boolean,
shiftKey: boolean,
timeStamp: number,
type: string,
xPos: number,
yPost: number
}
}
}

heartbeatReceived

Heartbeat event received
{
data: "heartbeatReceived"
}

orientationChanged

Device orientation has changed
{
data: {
type: "orientationChanged",
value: "landscape" | "portrait"
}
}

sessionRequested

Session has been requested
{
data: "sessionRequested"
}

userError

An error occurred while starting session
{
data: {
type: "userError",
value: string // error message
}
}

sessionQueued

You have entered a system-level queue (awaiting device availability)
{
data: "sessionQueued"
}

sessionQueuedPosition

Position of session queue
{
data: {
type: "sessionQueuedPosition",
position: number
}
}

accountQueued

You have entered an account-level queue (concurrent users)
{
data: "accountQueued"
}

accountQueuedPosition

Account queue position
{
data: {
type: "accountQueuedPosition",
position: number
}
}

appLaunch

App launch command sent
{
data: "appLaunch"
}

firstFrameReceived

First frame received
{
data: "firstFrameReceived"
}

timeoutWarning

Session is about to timeout in 10 seconds
{
data: "timeoutWarning"
}

sessionEnded

Session has ended
{
data: "sessionEnded"
}

screenshot

Screenshot data received
{
data: {
type: "screenshot",
data: string // base64 encoded image data
}
}

sessionConnecting

Passes the identifying token for the session
{
data: {
type: "sessionConnecting",
token: string,
path: string
}
}

chromeDevToolsUrl

URL to view dev tools for the device (only if network intercept enabled)
{
data: {
type: "chromeDevToolsUrl",
value: string
}
}

interceptResponse

Intercepted network response.
This is only emitted if network intercept enabled (proxy=intercept query param)
{
data: {
type: "interceptResponse",
value: {
cache: object
request: {
bodySize: number
cookies: Array<{ name: string, value: string }>
headers: Array<{ name: string, value: string }>
headersSize: number
httpVersion: string
method: string
queryString: Array<{ name: string, value: string }>
url: string
}
requestId: string
serverIPAddress: string
}
}
}

interceptRequest

Intercepted network request.
This is only emitted if network intercept enabled (proxy=intercept query param)
{
data: {
type: "interceptRequest",
value: {
cache: object
request: {
bodySize: number
cookies: Array<{ name: string, value: string }>
headers: Array<{ name: string, value: string }>
headersSize: number
httpVersion: string
method: string
queryString: Array<{ name: string, value: string }>
url: string
}
requestId: string
serverIPAddress: string
}
}
}

debug

Logged messages from the device.
This is only emitted if debug log is enabled (debug=true query param)
{
data: {
type: "debug",
value: string
}
}

deviceDimensions

The dimensions of the current device. If the screenOnly query param is true, the dimensions will be for the screen.
{
data: {
type: "deviceDimensions",
value: {
width: number,
height: number
}
}
}

app

Information for the application
{
data: {
type: "app",
value: {
name: "Example",
appDisplayName: "Example",
bundle: "com.example.app",
publicKey: "p7nww3n6ubq73r1nh9jtauqy8w",
platform: "ios"
}
}
}