A Zoom Rooms Controls profile is a JSON document you paste into the Zoom web portal. It puts buttons for your room equipment on the Zoom Rooms controller and can run commands automatically when a meeting starts or the microphone is muted. With a Q-SYS Core in the room, the profile speaks Q-SYS's External Control Protocol (ECP) directly — no extra control processor needed.
Zoom never published a full schema for these profiles; the reference is Zoom's own commented sample. Everything below follows that sample and the Q-SYS ECP documentation.
1. Prepare the Q-SYS design
ECP addresses controls by name, so every control the profile touches must be a Named Control in Q-SYS Designer: drag the control (a mute button, a gain, a snapshot trigger) into the Named Controls pane and give it a name such as RoomMute or SceneMeeting. Names are case-sensitive. Save the design to the Core and run it.
QSC also ships a ready-made Zoom Rooms Sample Design in Designer's Asset Manager. Its example profile only needs the Core IP edited.
2. The profile structure
{
"adapters": [
{
"model": "GenericNetworkAdapter",
"ip": "tcp://192.168.1.50:1702",
"ports": [
{
"id": "qsys_core",
"name": "Room Audio",
"methods": [
{
"id": "mute",
"name": "Room Mute",
"command": "csv RoomMute %\n",
"params": [
{ "id": "mute", "name": "Mute", "value": "1" },
{ "id": "unmute", "name": "Unmute", "value": "0" }
],
"type": "actions"
}
]
}
]
}
],
"rules": {
"microphone_muted": ["qsys_core.mute.mute"],
"microphone_unmuted": ["qsys_core.mute.unmute"]
}
}
- adapters — one per connection.
modelmust be one ofiTachIP2SL,iTachIP2CCorGenericNetworkAdapter; anything that is not a Global Cache iTach is aGenericNetworkAdapter. - ip — for a generic adapter it is a URL with the port:
tcp://<core-ip>:1702. Zoom refuses public IPs. - ports — the device. Each needs a unique
id; the controller shows itsname. - methods — the buttons.
commandis what gets sent;%is replaced by thevalueof the param the user taps.typeis"action"for a single button and"actions"when there are params.
3. ECP commands that work in a profile
| Goal | ECP line | Notes |
|---|---|---|
| Set a value (mute, gain) | csv RoomMute 1 | Number value |
| Set from text | css Input "HDMI 1" | Quote values with spaces |
| Press a trigger (snapshot, preset, volume step) | ct SceneMeeting | Trigger-type controls only |
Every command must end with a line feed — \n in JSON. The Core ignores a carriage return before it, so \r\n also works. Without the terminator the Core waits and nothing happens.
Test each line first: telnet <core-ip> 1702, type csv RoomMute 1, and watch the control move in Q-SYS. If it answers bad_id, the Named Control name is wrong.
4. Rules: automate on Zoom events
rules maps a Zoom event to a list of device.method.param commands:
"rules": {
"meeting_started": ["qsys_core.scene.meeting"],
"meeting_ended": ["qsys_core.scene.off"]
}
Documented events: meeting_started, meeting_ended, microphone_muted, microphone_unmuted, video_started, video_stopped, operation_time_started and operation_time_ended (Zoom Rooms 4.7.0+). There is no documented content-sharing event — names like sharing_started come from Zoom's webhook API, not from Room Controls.
5. Load it in Zoom
Zoom web portal → Room Management → Zoom Rooms → Edit on the room → Devices → enable Room Controls → Create Profile → paste the JSON → Save. A Room Controls icon appears on the controller.
Common mistakes
These are the errors we see most in profiles people bring to JSON AI Studio:
- Inventing a model name.
"model": "Q-SYS Core110f"or"GenericNetworkDevice"is rejected. Use"GenericNetworkAdapter"and put the Core's details inip. - Methods directly on the adapter. They belong inside
ports[].methods. - Template syntax that is not Zoom's.
{{param}}placeholders are not substituted — Zoom only replaces%. - Using
sgas a command.sgis ECP's status/keep-alive request; it does not change anything. Usecsv,cssorct. - Missing
\n. The Core never executes a line without the terminator. - Controls that are not Named Controls. ECP replies
bad_id; export the control in Designer. - Port 1710. That is the JSON-RPC protocol; Zoom profiles send ECP text, which is port 1702.
Edit it with AI
Open the template in JSON AI Studio and describe the change — "add a scene that recalls the presentation preset", "mute the room when Zoom mutes". Paste your own profile and ask "is this valid for Zoom Rooms?" to get each suggested fix with the reason behind it.