description |
---|
Interact with the virtual device via a Javascript post-message API |
{% hint style="danger" %} Cross-document messages API is no longer receiving updates.
Please use our Javascript SDK for any new development. {% endhint %}
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 }, '*')
Equivalent to clicking play
postMessage('requestSession', '*')
Taps the home button for iOS apps when available
postMessage('emitHomeButton', '*')
Rotates counter-clockwise
postMessage('rotateLeft', '*')
Rotates clockwise
postMessage('rotateRight', '*')
Sets device scale to a value between 10 and 100
postMessage({ type: 'setScale', value: 50 })
Prompts user to download screenshot
postMessage('saveScreenshot', '*')
Sends screenshot data directly to parent window. See the screenshot
event the iFrame posts to the parent.
postMessage('getScreenshot', '*')
Sends heartbeat to prevent inactivity timeout
postMessage('heartbeat', '*')
Sends click event at the provided coordinates
postMessage({ type: 'mouseclick', x: 100, y:100 }, '*')
Pastes the provided text
postMessage({ type: 'pasteText', value: 'Hello World' }, '*')
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"
Sets language, restarts app
postMessage({ type: 'language', value: 'fr' }, '*')
Sets location. value
should be 2-length array that contains [latitude, longitude]
postMessage({ type: 'location', value: [50.0, -100.0] }, '*')
Opens deep-link or regular URL in Safari
postMessage({ type: 'url', value: 'https://appetize.io' }, '*')
Send shake gesture to iOS apps
postMessage('shakeDevice', '*')
Sends Android KEYCODE_MENU command
postMessage('androidKeycodeMenu', '*')
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/'
}, '*')
(Android 8+ only) simulate a matching fingerprint
postMessage('biometryMatch', '*')
(Android 8+ only) simulate a non-matching fingerprint
postMessage('biometryNonMatch', '*')
Disables all user interactions
postMessage('disableInteractions', '*')
Re-enables all user interactions
postMessage('enableInteractions', '*')
Kills and restarts app in same session
postMessage('restartApp', '*')
Ends the session
postMessage('endSession', '*')
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)
})
Session has received an interaction from the user
{
data: {
type: "userInteractionReceived",
value: {
altKey: boolean,
shiftKey: boolean,
timeStamp: number,
type: string,
xPos: number,
yPost: number
}
}
}
Heartbeat event received
{
data: "heartbeatReceived"
}
Device orientation has changed
{
data: {
type: "orientationChanged",
value: "landscape" | "portrait"
}
}
Session has been requested
{
data: "sessionRequested"
}
An error occurred while starting session
{
data: {
type: "userError",
value: string // error message
}
}
You have entered a system-level queue (awaiting device availability)
{
data: "sessionQueued"
}
Position of session queue
{
data: {
type: "sessionQueuedPosition",
position: number
}
}
You have entered an account-level queue (concurrent users)
{
data: "accountQueued"
}
Account queue position
{
data: {
type: "accountQueuedPosition",
position: number
}
}
App launch command sent
{
data: "appLaunch"
}
First frame received
{
data: "firstFrameReceived"
}
Session is about to timeout in 10 seconds
{
data: "timeoutWarning"
}
Session has ended
{
data: "sessionEnded"
}
Screenshot data received
{
data: {
type: "screenshot",
data: string // base64 encoded image data
}
}
Passes the identifying token for the session
{
data: {
type: "sessionConnecting",
token: string,
path: string
}
}
URL to view dev tools for the device (only if network intercept enabled)
{
data: {
type: "chromeDevToolsUrl",
value: string
}
}
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
}
}
}
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
}
}
}
Logged messages from the device.
This is only emitted if debug log is enabled (debug=true
query param)
{
data: {
type: "debug",
value: string
}
}
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
}
}
}
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!