2023.2 EN DE

    Show / Hide Table of Contents

    WebSocket API Settings

    Description

    The WebSocket API allows external tools to control X-Creator and receive live presentation state over a persistent WebSocket connection, instead of polling. Once connected, the server pushes the full current state (experience list, and — once joined — the current experience, its slide list, its media pool, the active slide and that slide's live media layers) and then keeps the client up to date with events as the state changes, so a client never needs to poll for changes. Live layer edits (move, resize, rotate, add, remove, …) made on the X-Creator side are pushed without requiring a save.

    The API is available at ws://<ip>:<port>/ws. Requests are JSON text messages; example of a valid connection URL: ws://192.168.0.1:9698/ws

    Environment Configuration

    Enable the WebSocket API module so it is available for the Environment.

    X-Creator Configuration

    Enable the WebSocket API module for one X-Creator in the Environment that should receive the WebSocket connections and use the IP of this X-Creator when connecting.

    Port
    The port on which connections are accepted (default 9698)

    Authentication
    Enables to define a Bearer Token that must be supplied when connecting. Since browsers cannot set custom headers on a WebSocket handshake, the token is passed as a query parameter on the connection URL instead of a header: ws://192.168.0.1:9698/ws?token=<token>. A connection with a missing or invalid token is sent {"type":"error","message":"Unauthorized"} and immediately closed.

    API Documentation

    Message Format

    Every message, in both directions, is a single-line JSON object. Incoming frames larger than 1 MiB are rejected and the connection is closed.

    Because of that this API carries no bulk or binary payloads, which is why downloading an X-Creator's log files exists only on the REST API — see REST API.

    Commands (client → server)

    { "command": "slides/activate", "id": "<slideId>" }
    

    command is required; id is only required by commands that operate on a specific slide, layer, media item or experience; name is only required by slides/rename; layer is only used by layers/update. The media control commands (see Media Control Commands), along with slides/timer and auto-forward/delay, use a handful of generic, reused argument fields instead of dedicated ones per command: value (number), intValue (int), boolValue (bool), text (string), color ({ "r", "g", "b", "a" }), and the strongly-typed videoPlayMode, webNavigation, ndiColorFormat, ndiBandwidth, textAlignment (each a string enum member). Which fields a command reads is documented per command below.

    Responses (server → client)

    { "type": "response", "command": "slides/activate" }
    

    Sent once per command, in reply to that command. Some commands include additional fields alongside command (see the command list below).

    The slide navigation commands (slides/next, slides/previous, slides/activate) ask the server of the shared experience to change the active slide, so that all clients of that experience show the same slide. Their response confirms that the request was accepted and passed on, not that the slide has already changed. The server can decide not to carry a request out, for example when it arrives immediately after another slide change; no slide changes then, and the response is still a normal response rather than an error. Wait for the slide/changed event to see which slide actually became active.

    Errors (server → client)

    { "type": "error", "command": "slides/activate", "message": "Slide 'abc' not found" }
    

    Sent instead of a response when a command fails. command is omitted when the message itself could not be parsed (invalid JSON, or missing command field).

    Events (server → client)

    { "type": "event", "event": "slide/changed", "name": "Intro", "id": "abc", "isFavorite": false }
    

    Sent by the server on its own, without a preceding command, whenever presentation state changes. See "Events" below.

    Connecting

    Right after the WebSocket handshake completes, the server sends:

    1. {"type":"event","event":"ready"} — signals that the server is now processing commands.
    2. experiences/list event.
    3. clients/list event.
    4. If already joined to an experience: experience/changed, slides/list, chapters/list, media/list, auto-forward/state, (if a slide is active) slide/changed and slides/current/layers events.

    The experiences/list and clients/list snapshot events are not gated on being joined to an experience — both are meaningful before that too. The rest of the set is pushed again whenever an experience is joined. A client can therefore rely entirely on this initial snapshot plus subsequent events and never has to send a command just to learn the current state.

    Commands

    Command id required Description
    alive Checks that the server is responding.
    slides/list Returns a list of all slides from the current experience, each with its name, ID, favorite flag and timerSeconds.
    slides/current Returns name, ID, favorite flag and timerSeconds of the current slide.
    slides/current/layers Returns the media layers of the currently active slide as Media layer objects.
    slides/next Loads the next slide from the current experience. Commands arriving close together are collected into a single move covering all of them, so intermediate slides are skipped rather than each being loaded.
    slides/previous Loads the previous slide from the current experience. Same collecting behavior as slides/next.
    slides/activate yes (slide ID) Loads the slide with the given ID from the current experience.
    slides/layers yes (slide ID) Returns the media layers of the slide with the given ID from the current experience as Media layer objects.
    slides/save Saves the currently active slide, capturing its current media layers and controls.
    slides/rename yes (slide ID) + name Renames the slide with the given ID to name.
    slides/delete yes (slide ID) Deletes the slide with the given ID. If it is the currently active slide, a neighboring slide is activated first.
    slides/timer yes (slide ID) + intValue Sets how long the slide with the given ID is shown before auto-forward moves on, in whole seconds. Zero removes the timer, the same as slides/timer/clear. No upper bound; a negative value is rejected. Setting the timer of the active slide restarts its countdown from the new duration.
    slides/timer/clear yes (slide ID) Removes the timer from the slide with the given ID. The auto-forward delay still applies to it afterwards.
    chapters/list Returns a list of all chapters, each with its slides, from the current experience. See Chapter object.
    chapters/get yes (chapter ID) Returns the chapter with the given ID from the current experience. See Chapter object.
    chapters/activate yes (chapter ID) Loads the first slide of the chapter with the given ID from the current experience.
    auto-forward/state Returns the auto-forward countdown of the current experience. See Auto-forward.
    auto-forward/delay no, takes intValue Sets the auto-forward delay of the current experience in whole seconds, applying to every slide without a timer of its own. Zero switches auto-forward off. See Auto-forward.
    auto-forward/pause Pauses the running countdown. Errors if no countdown is running.
    auto-forward/resume Resumes the paused countdown, which carries on from where it stopped. Errors if no countdown is running, or if the presentation is frozen.
    media/list Returns every media item known to the currently joined experience, independent of slide or layer placement.
    media/layer yes (media ID) Creates a new media layer for the given media on the currently active slide, positioned near the center of the visible canvas; returns the created Media layer object.
    layers/get yes (layer ID) Returns the media layer with the given ID on the currently active slide as a Media layer object, control state included. Refreshes one layer — including a playing video's position — without pulling the whole slide.
    layers/update yes (layer ID) + layer Applies a partial update to the media layer with the given ID on the currently active slide. The layer field holds a Media layer object with only the properties to change (see Updating a layer).
    layers/delete yes (layer ID) Deletes the media layer with the given ID from the currently active slide, including its control state.
    experiences/list Returns a list of all experiences with names, IDs and if set as favorites.
    experiences/current Returns name, ID, favorite flag and canvas dimensions of the current experience.
    experiences/slides yes (experience ID) Returns a list of all slides for the experience with the given ID, without joining it. If this X-Creator hasn't loaded that experience yet, it is fetched from X-Manager on demand. Only available on a X-Creator running the Host role.
    experiences/chapters yes (experience ID) Returns a list of all chapters, each with its slides, for the experience with the given ID, without joining it. Same on-demand fetch and Host-role restriction as experiences/slides. See Chapter object.
    experiences/join yes (experience ID) Joins the experience with the given ID. If the experience already has a client with sync enabled, this client joins with sync forced off, matching the app's own join behavior.
    experiences/leave Leaves the current experience. Errors if no experience is currently loaded.
    clients/list Returns every connected client as Client objects.
    clients/current Returns the client answering this request as a Client object.
    clients/get yes (client ID) Returns the client with the given ID as a Client object.
    x-manager/info Returns the X-Manager this X-Creator is connected to. See X-Manager info.
    version/info Returns the running build. See Version info.
    config/get Returns the X-Creator configuration this instance runs under. See Config info.
    config/set no, takes configName + environmentName Selects the X-Creator configuration this instance runs under, taking effect on the next start; does not restart. Errors if either name is missing, if no configuration with that name exists in that environment, or if the X-Manager could not be reached to resolve them. See Config info.
    config/list Returns every X-Creator configuration the connected X-Manager offers — the names config/set can be given. Errors if the X-Manager could not be reached. See Config list.
    environment/list Returns every environment the connected X-Manager holds — where the environmentId the commands below take comes from. See Administrator commands.
    license/list Returns every license the connected X-Manager holds, without their keys. See Administrator commands.
    config/environment yes (configuration ID), plus environmentId Moves an X-Creator configuration to another environment on the X-Manager. See Administrator commands.
    license/environment yes (license ID), plus environmentId Moves a license to another environment on the X-Manager. See Administrator commands.
    shortcuts/trigger no, takes shortcut Fires an app-side shortcut, exactly as pressing its key combination would. See Triggering a shortcut.
    shortcuts/get no, takes shortcut Returns the current state of a shortcut that has readable state. See Reading shortcut state.

    Media-type-specific operations (play/pause, page navigation, etc.) are listed separately in Media Control Commands.

    Any unrecognized command value returns {"type":"error","command":"<command>","message":"Unknown command"}.

    Response payloads

    Successful responses carry their data alongside type and command as follows:

    Command Payload
    slides/list array under slides
    slides/current/layers array under layers
    slides/layers array under layers, plus the requested id echoed
    chapters/list array under chapters
    chapters/get chapter object under chapter, plus the requested id echoed
    media/list array under media
    media/layer created layer object under layer
    layers/get layer object under layer, plus the requested id echoed
    experiences/list array under experiences
    experiences/slides array under slides, plus the requested id echoed
    experiences/chapters array under chapters, plus the requested id echoed
    slides/current name, id, isFavorite, timerSeconds inline on the envelope
    auto-forward/state slideId, running, durationMs, remainingMs, delaySeconds inline on the envelope
    experiences/current name, id, isFavorite, canvasWidth, canvasHeight inline on the envelope
    shortcuts/get enabled inline on the envelope
    clients/list array under clients
    clients/current Client object fields inline on the envelope
    clients/get client object under client, plus the requested id echoed
    x-manager/info url, version, publicFeatureEnabled inline on the envelope
    version/info version, branch, commit, buildTime, buildKind inline on the envelope
    config/get, config/set configId, configName, environmentId, environmentName, source inline on the envelope
    config/list array under configs
    environment/list array under environments
    license/list array under licenses
    config/environment configId, configName, environmentId, environmentName inline on the envelope
    license/environment licenseId, licenseName, environmentId, environmentName, isValid inline on the envelope

    All other commands (alive, navigation, save, rename, delete, join, leave, updates, shortcut triggers) reply with just { "type": "response", "command": "<command>" }.

    Chapter object

    The chapter commands and events (chapters/list, chapters/get, experiences/chapters, chapters/list event) describe a chapter with this object. A chapter is an ordered group of slides; every slide in an experience belongs to exactly one chapter.

    Field Type Description
    name string Display name of the chapter.
    id string Unique ID of the chapter.
    slides array The chapter's slides, in order, each as { "name", "id", "isFavorite" } (same shape as slides/list, without timerSeconds).

    Media layer object

    The layer commands and events (slides/current/layers, slides/layers, media/layer, layers/update, and the slides/current/layers event) describe each media layer with this object. Transform values are normalized rather than in pixels:

    Field Type Description
    mediaLayerId string Unique ID of the layer.
    mediaId string ID of the media the layer displays.
    mediaType string Media type, e.g. Image, Video, Text, Web, AssetBundle, Shape.
    name string Display name of the media.
    position { "x", "y" } Normalized position. x spans the canvas width, y spans the canvas height (0–1 covers the canvas).
    size { "x", "y" } Normalized size. Both x (width) and y (height) are relative to the canvas width.
    rotation number Rotation in degrees.
    crop { "x", "y", "z", "w" } Crop fractions (0–1) per edge: x=top, y=bottom, z=left, w=right. Also adjusts position/size to match, unless those are set in the same request.
    visible bool Whether the layer is shown.
    alpha number Opacity, 0–1.
    zOrder int Stacking order; higher values are drawn in front. Relative only — not guaranteed 0-based or contiguous, and values differ between the active slide (normalized) and other slides (raw stored values).
    locked bool Whether the layer is locked against edits.
    fixedAspectRatio bool Whether width and height stay locked to the media's aspect ratio.
    fullscreen bool Whether the layer fills the whole canvas.
    sectionFullscreen bool Whether the layer fills its section. Mutually exclusive with fullscreen.
    backgroundColor { "r", "g", "b", "a" } Background color behind the media, each channel 0–1.
    isStatic bool Whether the layer is static (persists across every slide). Toggling this also re-maps layerGroup to/from its Static* variant.
    layerGroup string Layer group: Background, Regular, Foreground, StaticBackground, StaticRegular, StaticForeground. Setting a non-static base group (e.g. Foreground) while the layer is static resolves to its Static* counterpart automatically. System-assigned groups (Widget, VideoSource, Audio) can't be set through the API.
    control object or null Media-type-specific control state snapshot, shaped per mediaType — see Media control object. null for media types with no control operations (e.g. Image, AssetBundle, VideoMatrix).

    Media control object

    Every response/event that includes a Media layer object nests the layer's current control state under control, shaped according to its mediaType. To read it for a single layer, use the layers/get command.

    mediaType Fields
    Video isPlaying (bool), playMode (string: Loop, ResetAfterPlay, PlayToEnd, ForwardSlideWhenFinished), volume (0–1), muted (bool), position (0–1, normalized over duration), duration (seconds)
    Audio isPlaying (bool), loop (bool), volume (0–1), muted (bool), position (0–1, normalized over duration), duration (seconds)

    duration is the media's total length in seconds, so position * duration gives the elapsed time — enough to show and seek to a real timecode. It is 0 when the length isn't known (media without duration metadata). | Pdf | currentPage (int, 0-based), interaction (bool) | | Web | webUrl (string) | | Ndi | volume (0–1), muted (bool), colorFormat (string: BGRX_BGRA, UYVY_BGRA, RGBX_RGBA, UYVY_RGBA, Fastest), bandwidth (string: Highest, Lowest, AudioOnly) | | Text | text (string), fontName (string), fontSize (number), fontColor ({ "r", "g", "b", "a" }), alignment (string, Unity TextAnchor member, e.g. UpperLeft), interaction (bool) | | Shape | color ({ "r", "g", "b", "a" }) | | everything else | null — no control operations are exposed for this media type |

    Client object

    The client commands and events (clients/list, clients/current, clients/get) describe a connected client with this object, sourced from the server's internal client-info state rather than a separate schema per client type:

    Field Type Description
    clientId string Unique ID of the client.
    clientName string Display name of the client, or empty if unset.
    clientType string Client role, e.g. Visualisation, Control.
    connectionId int Internal network connection handle, mainly useful for debugging. Not stable across reconnects.
    address string Address this client can be reached at, as the host observes it on its connection. Empty on a client that has not registered with a host yet. Together with restPort this is what lets a caller address another client's own API without being told where it runs.
    restPort int Port this client serves its REST API on, or 0 when the REST API is switched off for it (or has not started yet).
    syncEnabled bool Whether this client follows another client's slide navigation.
    experienceId string ID of the experience this client has joined, or empty if none.
    slideId string ID of the slide this client currently has active, or empty if none.
    slideLoadState string How far the client has got loading slideId, e.g. None, Loading, Settled.
    autoPlayDelayMs int Configured auto-forward delay for this client in milliseconds, or 0 if auto-play is off.
    downloadProgress int Media download progress, 0–100.
    ndi object enabled (bool), mediaIds (array of string) — whether NDI is enabled on this client and which media it currently sources over NDI.
    hardwareInfo object deviceType (string, Unity DeviceType member), deviceName (string), systemMemorySize (int, MB), processorFrequency (int, MHz), graphicsMemorySize (int, MB).

    The list is only as current as the server's own broadcast — a Control client reads the same continuously-synced copy as the host, so the commands and the clients/list event work the same regardless of which client answers.

    X-Manager info

    The x-manager/info command describes the X-Manager this X-Creator is connected to with these fields:

    Field Type Description
    url string Address of the X-Manager as configured in X-Creator, a full base URL with scheme, host and port (e.g. https://x-manager.example.com:3001) rather than a bare IP.
    version string Release version of the X-Manager, e.g. 2023.2.279 (develop). Empty until the X-Manager has been reachable at least once.
    publicFeatureEnabled bool Whether the public feature is enabled on the X-Manager. Read from the X-Manager's own settings, not inferred from whether X-Creator currently holds a public token. false until the X-Manager has been reachable at least once.

    version and publicFeatureEnabled are read from the X-Manager when the backend connection comes up and re-read on every reconnect, so a setting changed on the X-Manager is picked up without restarting X-Creator. Every X-Creator reads them for itself, so the answer does not depend on which instance is asked.

    Version info

    The version/info command describes the running build with these fields:

    Field Type Description
    version string Application version including the build number, e.g. 2023.2.279.
    branch string Branch the build came from, e.g. develop or staging. Empty for a production build, and for a locally made build, which carries no build manifest.
    commit string Commit the build came from. Empty when no build manifest is present.
    buildTime string When the build was made. Empty when no build manifest is present.
    buildKind string production, or agent-api for a build carrying the extra unauthenticated agent interface. Decided at compile time, so a production build answers this too rather than the question only being answerable where that interface exists.

    Config info

    The config/get and config/set commands describe the X-Creator configuration this instance runs under with these fields. Everything here is per instance: each X-Creator is served its own configuration, so ask the instance you mean rather than the host.

    Field Type Description
    configId string ID of the X-Creator configuration, as registered on the X-Manager. Reflects whatever was last selected (welcome screen or config/set), not re-fetched by this command.
    configName string Name of that configuration. This is the same value the Client object reports as clientName. Same caveat as configId.
    environmentId string ID of the environment the configuration belongs to.
    environmentName string Name of that environment. Empty until the X-Manager has served this instance its client info at least once, since only the X-Manager knows the name behind the id.
    source string Whether environmentId/environmentName came from the X-Manager this run: x-manager when it served them, cached when it could not be reached and the previous run's values were kept, unknown before either has happened. Does not describe configId/configName, which this command never re-fetches.

    source is worth reading before trusting the environment fields: startup deliberately carries on with the previous run's environment info when the X-Manager is unreachable, and it looks no different from a freshly-served value once in place. Since both requests are keyed only by client id, resolved independently server-side, a cached environment is not just possibly stale but possibly wrong for what this instance is actually running — the X-Manager can have reassigned this client to a different environment in the meantime, and the license/config the app is running under would already reflect that even though environmentName here still doesn't.

    config/set selects by name rather than by id, because the X-Manager mints new ids whenever its content is reimported while names stay put. environmentName is required as well, since configuration names are only unique within one environment. It takes effect on the next start and deliberately does not restart the application — nothing is torn down at the moment of the call, and until the restart happens the instance keeps running under its previous configuration while reporting the new one.

    { "command": "config/set", "configName": "Visualisation Left", "environmentName": "Showroom" }
    

    Config list

    The config/list command returns every X-Creator configuration the connected X-Manager offers, as an array under configs. Unlike Config info this says nothing about what the asked instance is running — it is the list to pick from, not a report about the instance.

    Field Type Description
    configId string ID of the X-Creator configuration, as registered on the X-Manager. Not accepted by config/set, and not stable across a reimport.
    configName string Name of that configuration. This, paired with environmentName, is what config/set selects by.
    environmentId string ID of the environment the configuration belongs to.
    environmentName string Name of that environment. Needed alongside configName to address a configuration, since names are only unique within one environment.

    The list comes from the X-Manager itself rather than from anything held locally, so this needs it to be reachable and errors when it is not.

    Administrator commands

    config/environment and license/environment do not change this instance but the X-Manager's own records, so that an automated setup can move an X-Creator between environments without anyone opening the X-Manager UI.

    Because of that they need more than this API's bearer token: the X-Creator forwards them to the X-Manager under the credential of the user logged in on this instance, and the X-Manager only accepts them from a member of its Administrators group. There is no second credential to fall back on, so an instance that is not logged in as such a user returns an error naming which of these applies: it accesses the X-Manager with an API token, which is minted without administrator rights; no X-Manager user is logged in on it, including when it runs in public mode; or the logged-in user is not in the Administrators group. The X-Manager can also refuse the change itself after that check passed, for instance when the user's group membership changed since the login.

    Both address their target by id and the environment by environmentId, because the X-Manager identifies these records by id rather than by name. None of these ids survive a reimport of the X-Manager's content, so they are read fresh:

    • environment/list returns every environment as environmentId + environmentName under environments. This is how an environment name becomes an id, and it reaches environments that config/list cannot — that one only shows environments which already have a configuration, which is exactly what a configuration is usually moved away from.
    • license/list returns every license under licenses, with the fields below and never a key. It also shows which environment currently holds the license.

    Both lists are plain reads and need no administrator credential of their own, only whatever the X-Manager requires to serve them.

    config/environment moves an X-Creator configuration to another environment. Instances running that configuration are served the new environment's settings from their next start. A configuration belongs to exactly one environment, which is why this is a separate command rather than a field on config/set. The response repeats the Config list fields. environmentName is resolved separately, because the X-Manager's answer to this command names the environment by id only; it is null if that lookup failed — the move itself has already happened by then and is not reported as failed over it.

    { "command": "config/environment", "id": "6634f1b2c8a94d0012ab9f01", "environmentId": "6634f1b2c8a94d0012ab34cd" }
    

    license/environment moves a license to another environment. An environment without a license cannot be started on: an X-Creator moved to it fails during startup with an invalid-license error rather than a configuration error. A license record carries one environment, so this re-points it rather than copying it: the environment it was on loses this license, and whether that leaves it unlicensed depends on whether another license still covers it. A trial is the exception — there is only one per installation, so it cannot cover two environments and has to be moved between them. The license does not have to be deactivated first, and its key is never part of the request or the response.

    { "command": "license/environment", "id": "6634f1b2c8a94d0012abcd77", "environmentId": "6634f1b2c8a94d0012ab34cd" }
    
    Field Type Description
    licenseId string ID of the license on the X-Manager.
    licenseName string Name of that license.
    environmentId string ID of the environment the license now applies to.
    environmentName string Name of that environment. Looked up separately when the license document does not carry it, and null if that lookup failed.
    isValid boolean Whether the license covers the environment it now belongs to. false does not mean the change failed — the move succeeds either way, but an X-Creator on that environment then fails to start with an invalid-license error.

    Auto-forward

    Auto-forward moves the presentation on by itself. How long a slide is shown is resolved from two settings: the slide's own timerSeconds if it has one, otherwise the experience's auto-forward delay, which applies to every slide without a timer.

    The auto-forward/state response and event carry the countdown:

    Field Type Description
    slideId string The slide the countdown is running for, empty when none is running.
    running bool Whether the countdown is running rather than paused.
    durationMs int How long the countdown runs in total.
    remainingMs int How much was left when the event was sent.
    delaySeconds number The auto-forward delay, 0 when auto-forward is off. Fractional when it comes from a client configuration that is not a whole number of seconds.

    The countdown does not tick over the network — auto-forward/state is only pushed when it starts, stops, is paused or resumed, or when the delay changes. A client wanting a live readout counts remainingMs down against its own clock from the moment the event arrived, exactly as the app's own timer ring does.

    Pause and resume are unowned: a countdown paused through the API is resumed by the app's own timer ring just as readily as by auto-forward/resume, and vice versa. Naming the operation rather than toggling also makes it idempotent — sending auto-forward/pause twice succeeds and changes nothing. Pausing is allowed while the presentation is frozen (freeze already holds the countdown, and pausing on top of it is what keeps it from resuming when freeze is lifted); resuming while frozen is rejected.

    auto-forward/delay overrides the delay taken from client configuration for as long as the server runs; a restart falls back to client configuration, and nothing is written to any configuration file. Zero switches auto-forward off — there is no separate enable/disable and no remembered previous value. A countdown already running for a slide without its own timer restarts from the new delay, as it does when that slide's own timer is changed.

    There is no restart command: reloading the slide restarts its countdown.

    Media Control Commands

    All commands below take id (a mediaLayerId) and reply with just { "type": "response", "command": "<command>" } on success, or an error using the same conditions as other layer commands (Missing id, Media layer '<id>' not found, or a "has no X control state" message when the layer's mediaType doesn't support the operation).

    Scope — some operations apply only to the targeted layer instance ("Layer"); others apply to every layer currently showing the same media item ("Media"), e.g. muting one placement of a video mutes all of them. A control-state change (from any client) also triggers a slides/current/layers event, same as a transform edit.

    Volume and mute — the video/volume, audio/volume, and ndi/volume commands also set mute, mirroring the volume slider in the app: a volume above 0 unmutes, a volume of 0 mutes. The app's slider reads as 0 for as long as mute is set, whatever volume is behind it, so a volume change that left mute untouched would not be visible there. Send */mute after */volume if the two need to be set independently.

    Video (all Media-scoped)

    Command Fields Description
    video/play boolValue (isPlaying) Play or pause at the media's current position; never seeks.
    video/seek value (position) Seek without changing play state. 0–1, normalized over the media's duration.
    video/mode videoPlayMode Loop, ResetAfterPlay, PlayToEnd, or ForwardSlideWhenFinished.
    video/volume value 0–1. Also unmutes, or mutes at 0.
    video/mute boolValue

    Audio (all Layer-scoped)

    Command Fields Description
    audio/play boolValue (play) Play or pause at the media's current position; never seeks.
    audio/position value Seek. 0–1, normalized over the media's duration.
    audio/loop boolValue
    audio/volume value 0–1. Also unmutes, or mutes at 0.
    audio/mute boolValue

    Pdf (all Layer-scoped)

    Command Fields Description
    pdf/page intValue (page) Jump to a 0-based page number.
    pdf/next-page none Advance one page, clamped to the last page.
    pdf/previous-page none Go back one page, clamped to page 0.
    pdf/first-page none Jump to page 0.
    pdf/last-page none Jump to the last page.
    pdf/interaction boolValue Toggles direct interaction (scrolling) with the PDF on the layer.
    pdf/enable-scrolling none Re-enables dispatching the current page while scrolling manually.

    Web (Layer-scoped)

    Command Fields Description
    web/url text (url) Loads a new URL.
    web/navigate webNavigation Back, Forward, or Reload.

    Ndi (all Media-scoped)

    Command Fields Description
    ndi/volume value 0–1. Also unmutes, or mutes at 0.
    ndi/mute boolValue
    ndi/color-format ndiColorFormat BGRX_BGRA, UYVY_BGRA, RGBX_RGBA, UYVY_RGBA, or Fastest.
    ndi/bandwidth ndiBandwidth Highest, Lowest, or AudioOnly.

    Text

    Command Scope Fields Description
    text/text Media text
    text/font Layer text (fontName)
    text/font-size Layer value (fontSize)
    text/font-color Layer color
    text/alignment Layer textAlignment Unity TextAnchor member, e.g. UpperLeft, MiddleCenter.
    text/interaction Layer boolValue

    Shape (Layer-scoped)

    Command Fields Description
    shape/color color

    Not exposed: freeze (any media type), NDI PTZ (ndi/ptz/*) and camera presets, Web scale/interaction/interaction-authority, and AssetBundle/VideoMatrix controls entirely.

    To convert normalized values to pixels, use the canvasWidth / canvasHeight fields from the experience/changed event or experiences/current response (default 1920×1080): xPx = position.x * canvasWidth, yPx = position.y * canvasHeight, widthPx = size.x * canvasWidth, heightPx = size.y * canvasWidth.

    Updating a layer

    layers/update carries a layer object containing only the properties to change; omitted properties are left untouched. At least one property must be present, otherwise the command errors with Missing layer properties.

    { "command": "layers/update", "id": "<layerId>", "layer": { "position": { "x": 0.25, "y": 0.5 } } }
    

    Notes:

    • position, size and crop are sent whole (all components), not per-axis.
    • rotation is an absolute value in degrees; the server applies the difference from the current rotation.
    • Setting fullscreen to true clears sectionFullscreen and vice versa (they are mutually exclusive).
    • Errors: Missing id, No active slide, Media layer '<id>' not found, Missing layer properties, or Layer group '<value>' cannot be set directly (system-assigned or unknown layerGroup).

    Triggering a shortcut

    shortcuts/trigger takes a shortcut name instead of an id and fires that shortcut's handlers, exactly as pressing its key combination on the X-Creator would. No experience needs to be joined.

    { "command": "shortcuts/trigger", "shortcut": "MouseCursor" }
    

    Only these three shortcuts are exposed:

    shortcut Key combination Effect
    MouseCursor Ctrl + M Shows or hides the mouse cursor.
    ShowWelcomeScreen Ctrl + W Shows or hides the welcome screen.
    ForceWindowFocus Alt + Shift + W Turns forcing focus on the X-Creator window on or off.

    MouseCursor and ShowWelcomeScreen are toggles that report no state, so this command can only flip them. ForceWindowFocus is the exception — read its resulting state back with Reading shortcut state below.

    Errors: Missing or unknown shortcut, or Shortcut '<name>' cannot be triggered remotely for a valid shortcut that is not in the list above.

    Reading shortcut state

    shortcuts/get takes a shortcut name and returns its current state. Only ForceWindowFocus supports this — MouseCursor and ShowWelcomeScreen are pure toggles with nothing to read back.

    { "command": "shortcuts/get", "shortcut": "ForceWindowFocus" }
    

    Response payload: enabled (boolean), inline on the envelope.

    Errors: Only 'ForceWindowFocus' has readable state for any other shortcut name, or Force window focus watcher is not active on this instance when the watcher isn't installed (editor, non-Windows, or server role).

    Events

    Events are pushed by the server without a matching command; a client should apply them to its local state as they arrive.

    Event Description
    ready Sent once right after connecting; the state snapshot described above follows immediately after.
    experiences/list The list of accessible experiences. Sent in the connect snapshot and re-sent whenever the list changes.
    clients/list The list of connected clients as Client objects. Sent in the connect snapshot and re-sent whenever any client's info changes — not gated on being joined to an experience.
    experience/state Informational only; state is joining or leaving while a join/leave is in progress. Does not drive client state by itself.
    experience/changed Sent once an experience join completes, together with the rest of the joined-experience snapshot. Includes canvasWidth and canvasHeight (pixels) for converting normalized layer values.
    experience/left Sent once the client has left its experience.
    slides/list The slide list of the currently joined experience; sent on join and re-sent whenever a slide is added, removed, renamed or otherwise changes.
    chapters/list The chapter list of the currently joined experience, each with its slides; sent on join and re-sent whenever a chapter is added, removed, renamed, or its slides change. See Chapter object.
    slide/changed Sent whenever the active slide changes, including right after a join completes.
    media/list The media pool of the currently joined experience; sent on join and re-sent whenever media is added or removed.
    auto-forward/state The auto-forward countdown; sent on join and on every transition, never on a tick. See Auto-forward.
    slides/current/layers The active slide's media layers as Media layer objects; sent on join, on slide change, and live as layers are edited. Continuous edits (e.g. a drag) are coalesced to at most one event per second.

    Samples

    Connect and load the next slide:

    { "command": "slides/next" }
    

    Get the media layers of the current slide:

    { "command": "slides/current/layers" }
    

    Rename a slide:

    { "command": "slides/rename", "id": "<slideId>", "name": "New name" }
    

    Move a layer and set its opacity (only the given properties change):

    { "command": "layers/update", "id": "<layerId>", "layer": { "position": { "x": 0.5, "y": 0.5 }, "alpha": 0.8 } }
    

    Tools

    Built-in Test Console

    Opening http://<ip>:<port>/ (the same host and port as the WebSocket endpoint) in a browser serves a built-in interactive console for connecting, sending commands and inspecting responses/events without any external tooling.

    Troubleshooting

    Connection is closed immediately after connecting

    If Authentication is enabled, the connection URL is missing a valid ?token=<token> query parameter. Check the Bearer Token configured for the X-Creator.

    Command returns {"type":"error", ...}

    The message field describes why the command could not be completed, e.g. a slide or experience ID that does not exist, or navigating past the last/first slide. This mirrors the equivalent REST API error conditions.

    No events are received after connecting

    Confirm the ready event was received first — if not, the handshake or authentication failed. If ready was received but no experience-specific events follow, no experience is currently joined; join one with experiences/join first.

    
    ☀
    ☾
    Back to top
    Generated by DocFX
    ☀
    ☾