Command reference
Send commands as JSON objects with a top-level type. See Getting started for connection and authentication, or download the AsyncAPI specification for every message schema.
Keep one command awaiting a response at a time: replies do not echo a client request ID. Check their type, because output events can arrive between responses. An expired client timeout does not cancel the operation.
Connection and controls
Section titled “Connection and controls”| Request | Parameters | Response |
|---|---|---|
AUTH | key: authentication key | AUTH_OK; otherwise AUTH_ERROR and disconnection |
events array | Input events, without a command type | No acknowledgement |
getState | None | state broadcast; see decoding |
The server sends CONNECT with info and authRequired on connection. Send AUTH first when required. Place commands at the root of the message, never inside events.
Profiles and mappings
Section titled “Profiles and mappings”| Request | Parameters | Response and data |
|---|---|---|
GET_CURRENT_MAPPINGS | None | CURRENT_MAPPINGS: {profile, profiles, mappings} |
GET_PROFILE_MAPPINGS | Required profile: name | PROFILE_MAPPINGS: {profile, mappings, requestId}; ignore requestId |
GET_TEMPLATE_PROFILES | None | TEMPLATE_PROFILES: array of {name, mappings, outputTypes} |
MCP_SWITCH_PROFILE | Required profile: name | MCP_PROFILE_SWITCHED: {profile, mappings} |
MCP_IMPORT_MAPPINGS | mode, mappings, and name for a new profile | MAPPINGS_IMPORTED: {profile, mappings, mode} |
{"type":"GET_PROFILE_MAPPINGS","profile":"Twitchat"}Names are matched without case sensitivity after trimming spaces. An unknown profile returns an empty mapping array when read; switching to it returns ERROR. Switching profiles follows the application’s subscription rules. The MCP_ commands are also available to ordinary WebSocket clients.
Import mappings
Section titled “Import mappings”Use mode: "new" with a non-empty name to create and activate a profile, or mode: "append" to add to the active profile. mappings is required; only the first 500 entries are retained. Appending replaces existing mappings with the same output.type and output.code. Save a copy before changing a profile.
A mapping contains input: {type, code, settings?} and output: {type, code, value}. It can also contain id, description, groupId, groupOperator, groupSettings, position, targetProfile and mute. Use an existing mapping or template as your starting point; the specification provides the supported fields and codes.
Descriptions are limited to 200 characters. New profile names are cleaned and limited to 50 characters; a duplicate name is an error. Invalid mappings return ERROR. Without a subscription, an in-app dialog asks how to import. Complete it promptly: a response can time out after 15 seconds while the import remains pending. Check the app before retrying.
Settings
Section titled “Settings”| Request | Parameters | Response and data |
|---|---|---|
GET_SETTINGS | None | SETTINGS_STATE: {settings, hints} |
SET_SETTING | Required key; either boolean value or toggle: true | SETTING_APPLIED: {key, value} |
settings contains the available boolean settings; hints explains selected keys. Use exactly one of value and toggle.
{"type":"SET_SETTING","key":"toggleOutput","value":false}Common keys are toggleOutput (live main output), toggleGamepad, toggleKeyboard, toggleMouseOutput, allowWebsocketOutput, websocketFullSpeed, toggleOverlay and autoStartMainOutput (startup behavior). releaseAll releases active controls: send value: true; the returned value is false because this is a one-shot action.
SET_SETTING cannot change allowSerialOutput, allowHIDOutput, unlockInputMute, toggleInputBlocking, requireWebsocketAuth, enableAnalytics, enablePostHog or enableCrisp. Change these in the application. Unknown or read-only keys return ERROR.
Enabling WebSocket, MCP or external AI disables automatic WebSocket output; enable output afterwards if needed. Disabling the last setting keeping the server active can close the connection before a reply arrives.
Navigation
Section titled “Navigation”| Request | Parameters | Response and data |
|---|---|---|
NAVIGATE_TO | Required page; optional tab, editMappingId, profile | NAVIGATED: {page, tab} |
GET_CURRENT_PAGE | None | CURRENT_PAGE: {page, tab, pathname}, values can be null |
Use a real application path, such as /dashboard, /discover, /mapping, /mapping-v2, /overlay, /inputs, /outputs, /facetester, /settings, /changelog, /premium, /gameDiscovery or /helpdesk. A missing leading slash is added. /agent opens a separate window; /gamepads and /connections are legacy redirects.
Tabs include gamepads, mobile, websocket-mcp for inputs; receiver, 8bitdo, opentrack for outputs; and options, design, advanced, whats-new, debug, account for settings. Some tabs depend on application settings.
On a mapping page, numeric editMappingId opens that mapping for editing; profile can select its profile. These fields take precedence over tab. NAVIGATED acknowledges the navigation request, not completion of the page. CURRENT_PAGE.page normally omits the leading slash; pathname includes it. /gameDiscovery is reported as game-discovery.
Windows, displays and cursor
Section titled “Windows, displays and cursor”These commands need the application’s native desktop controls and the relevant operating-system permissions. Keep PlayAbility running.
| Request | Parameters | Response and data |
|---|---|---|
LIST_WINDOWS | None | WINDOWS_LIST: {windows: [{id, name}]} |
GET_DISPLAYS | None | DISPLAYS_LIST: {displays: [...]} |
WINDOW_GET_PROPERTIES | Window selection below | WINDOW_PROPERTIES: {title, region: {left, top, width, height}} |
WINDOW_MOVE | Window selection; x, y (default 0, 0) | WINDOW_MOVED: {success: true} |
WINDOW_RESIZE | Window selection; width, height (default 800, 600) | WINDOW_RESIZED: {success: true} |
WINDOW_FOCUS | Window selection | WINDOW_FOCUSED: {success: true} |
GET_MOUSE_CURSOR_POSITION | None | MOUSE_POSITION: {x, y} |
To select a window, use windowTitle and optional windowTitleMatch: contains (default), exact or startsWith. Matching ignores case and selects the first result. Alternatively, use activeWindowOnly: true, which takes precedence over a title. With neither field, the active window is the default; activeWindowOnly: false then requires a title.
Window-list IDs are temporary enumeration indices, not selectors. Use finite coordinates and positive sizes. A missing matching window returns ERROR.
Each display has id, bounds, workArea, scaleFactor, scalePercent, rotation, isPrimary and label. Bounds and work areas contain {x, y, width, height} and can have negative coordinates. Cursor results are native coordinates; cursor input uses logical coordinates, so account for display scaling.
Screenshots
Section titled “Screenshots”Send TAKE_SCREENSHOT with these optional fields:
| Parameter | Values and defaults |
|---|---|
format | file (default), base64, both, dataUrl |
quality | JPEG quality, integer 1–100; default 80 |
maxWidth, maxHeight | Positive integers. maxWidth, otherwise maxHeight, otherwise 1024 sets a single maximum dimension for both sides. |
activeWindowOnly | Capture the active window |
windowTitle, windowTitleMatch | Capture a matching window; matching rules as above |
region | {x, y, width, height} within the screen; omitted fields use screen defaults |
Selection priority is active window → title → region → full screen. There is no displayId selector. Window capture reads a screen region, so obscured or minimized content may not be captured as expected.
SCREENSHOT_DATA.data contains width, height (capture dimensions before resizing) and timestamp (Unix milliseconds), plus:
| Format | Returned fields |
|---|---|
file | filePath: local temporary-directory path, not a URL |
base64 | buffer: raw Base64 string |
both | filePath and buffer |
dataUrl | dataUrl: string prefixed data:image/jpeg;base64, |
Saved files persist; manage their retention. Some installations can return PNG bytes despite JPEG metadata, so inspect the bytes if your client requires a guaranteed format.
Errors
Section titled “Errors”Errors have {type, error}, with a human-readable message. Most failures use ERROR; screenshot failures can use SCREENSHOT_ERROR, cursor lookup failures MOUSE_POSITION_ERROR, and invalid credentials AUTH_ERROR. There is no stable numeric error code or public request ID.
Unknown command types may receive no reply. Invalid input events may also receive no error. Add a timeout and handle disconnection; use the client examples as a starting point.