Cross-document messages

Interact with the virtual device via a Javascript post-message API

Cross-document messages API is no longer receiving updates.

Please use our Javascript SDK for any new development.

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"
        }
    }
}

Check out our JSFiddle.net example to see these messages in action!

Last updated