Skip to main content

useLumioAction

Execute a Lumio service action - a named operation on the host platform such as sending a chat message, changing an OBS scene, or emitting a custom event.

Signature​

const { execute, data, isLoading, error } = useLumioAction(actionType: LumioActionType);

Parameters​

ParameterTypeRequiredDescription
actionTypeLumioActionTypeYesThe action type to execute (e.g. "events:emit")

Return value​

PropertyTypeDescription
execute(params?: Record<string, unknown>) => Promise<void>Runs the action. The promise resolves once the action settled; a failure is reported in error, never as a rejection
dataunknown | nullThe action's return data from the last successful call (null when it returns none)
isLoadingbooleantrue while the action is in progress
errorstring | nullError message if the last call failed

How a call reaches Lumio​

execute() sends the JSON-RPC request action.execute ({ action, params }, typed as ActionExecuteParams in @zaflun/lumio-protocol) from your worker to the host page. The host forwards it to the Lumio API for your install — the API looks up which extension that install belongs to, so a worker cannot act as another extension — and the API checks that your lumio.config.json declares the action's permission before it runs anything.

Where an action can run:

SurfaceRuns asNotes
editor (widget editor in the dashboard)The signed-in streamer or team memberNeeds the extension-store:configure role permission on the account
layer in an overlay (OBS browser source)The overlay, via its own overlay linkOnly for an extension layer that is part of that overlay. The layer mounts only while the overlay's account has the extension installed and enabled. A shared overlay link (lm_share_…) cannot run actions. No chat:* actions (see below)
layer in a standalone widget (OBS browser source)The widget, via its own widget linkOnly for the widget's own install. No chat:* actions (see below)
Designer preview—No install exists yet, so every call fails with UNAVAILABLE

Overlay and widget links never run a chat:* action, whatever your manifest declares: those links are permanent and leak through stream captures, and a chat action runs as the account's bot. In an overlay or widget layer a chat:* call fails with DENIED (Permission denied: chat actions require a signed-in session, not an overlay or widget token). Use chat actions from the editor surface, or send chat from a bot module handler. Spotify, OBS and the other actions work in every surface above.

When a call fails, error holds the message and the host answers with one of these JSON-RPC error codes (ACTION_EXECUTE_ERRORS in @zaflun/lumio-protocol):

CodeNameMeaning
-32602INVALID_REQUESTaction is not a string or params is not an object
-32001UNAVAILABLEThis surface cannot run actions (no install, a shared link, or no signed-in session)
-32002DENIEDYour manifest does not declare the action's permission, the signed-in user may not configure extensions, or an overlay/widget layer called a chat:* action
-32003UNKNOWN_ACTIONThe Lumio API does not run this action type (see below)
-32004INVALID_PARAMSThe action's params are missing or malformed
-32005FAILEDThe action ran and failed, e.g. its target service is not connected

Supported action types​

Every action requires the permission of the same name in lumio.config.json. Actions that drive a connected service also need that service's plan feature on the installing account: feature:music for Spotify, feature:obs_remote for OBS, feature:multichat for chat. An action name that is not listed here returns an unknown-action error.

An action either takes effect or fails. When the service is not ready (Spotify not connected or no active device, OBS not connected), error carries the reason and nothing happens. An action never reports success for something it did not do.

Spotify​

Drives the player of the account's connected Spotify. Each action emits the same spotify:* event as the dashboard player, with source: "extension", so widgets listening for spotify:skip or spotify:volume react to it.

Action typeRequired permissionPayload
"spotify:play"spotify:play{ uri?: string } (resume, or start the given track URI)
"spotify:pause"spotify:pause{}
"spotify:skip"spotify:skip{ count?: number } (1-50, default 1)
"spotify:seek"spotify:seek{ position_ms: number }
"spotify:volume"spotify:volume{ volume_percent: number } (0-100)
"spotify:shuffle"spotify:shuffle{ enabled: boolean }
"spotify:repeat"spotify:repeat{ mode: "off" | "context" | "track" }
"spotify:queue_add"spotify:queue_add{ uri: string }

OBS​

Sent to the account's OBS remote connection, which confirms each command. If OBS is not connected, the action fails with OBS remote control is not connected.

Action typeRequired permissionPayload
"obs:set_scene"obs:set_scene{ scene_name: string }
"obs:set_source_visible"obs:set_source_visible{ source_name: string; visible: boolean; scene_name?: string } (default: the current program scene)
"obs:start_stream"obs:start_stream{}
"obs:stop_stream"obs:stop_stream{}
"obs:start_recording"obs:start_recording{}
"obs:stop_recording"obs:stop_recording{}

Chat​

Chat actions run as the account's bot, never as a person's login. On the platform, a message or moderation action shows up as coming from the bot. platform is "twitch", "kick" or "youtube".

Action typeRequired permissionPayload
"chat:send"chat:send{ platform: string; message: string } (1-500 characters)
"chat:delete"chat:delete{ platform: string; message_id: string }
"chat:ban"chat:ban{ platform: string; user_id: string; reason?: string }
"chat:unban"chat:unban{ platform: string; user_id: string }
"chat:timeout"chat:timeout{ platform: string; user_id: string; duration_secs: number; reason?: string } (1-1209600)
  • chat:send goes to the bot that serves the account's chat on Twitch, Kick or YouTube (on Twitch, that is the shared Lumio bot). It fails with bot_not_connected when no bot is running for that platform. It is never queued for later.

  • Moderation (chat:delete, chat:ban, chat:unban, chat:timeout) uses the account's own bot connection on that platform. The shared Lumio bot does not moderate for extensions. The bot must be a moderator of the channel (on Twitch: /mod <bot>). Supported platforms:

    Platformdeletebantimeoutunban
    Twitchyesyesyesyes
    YouTubeyesyesyesno
    Kicknononono

    A Twitch bot connected before moderation was available lacks the moderation scopes. Its chat keeps working, but moderation fails with bot_scope_missing until the streamer reconnects the bot.

  • A moderation action that took effect appears in the account's moderation log with the bot as moderator, and in the account's audit log as account:extension_moderation (the reason text is not recorded there).

Events​

Action typeRequired permissionPayload
"events:emit"events:emit{ event_type: string; data?: unknown }

Overlay​

Action typeRequired permissionPayload
"overlay:update_layer"overlay:update_layer{ overlay_id: string; layer_id: string; config: unknown }

Errors​

SituationuseLumioAction() codeMessage
Unknown action nameUNKNOWN_ACTIONUnknown action: <name>
Malformed payloadINVALID_PARAMSInvalid params: <reason>
Permission not declared in the manifestDENIEDPermission denied: Extension does not declare the required permission: <permission>
Plan feature not on the account's planDENIEDFeature '<feature>' is not available
Service not ready or upstream failureFAILEDThe reason; nothing happened

Chat actions that are refused fail with FAILED in useLumioAction(). The API response also carries a stable code for them (error_code on REST POST /v1/extension-installs/{install_id}/actions/{action}, errorCode on GraphQL executeExtensionAction):

error_codeMeaning
bot_not_connectedNo bot is running (chat:send), or the account has no own bot connection for moderation, or it must be reconnected
bot_scope_missingThe bot connection lacks the moderation permission; reconnect the bot
moderation_forbiddenThe bot is not a moderator in the channel
platform_not_supportedThe action is not available on this platform (see the table above)
moderation_failedThe platform refused the action for another reason (for example, no live YouTube broadcast)
internal_errorLumio could not read the bot connection or reach the bot

Example: Send a chat message​

import { Lumio, CompactView, Button, TextField, useLumioAction } from "@zaflun/lumio-sdk";
import { useState } from "react";

function ChatPanel() {
const { execute: sendMessage, isLoading, error } = useLumioAction("chat:send");
const [message, setMessage] = useState("");

const handleSend = async () => {
await sendMessage({
platform: "twitch",
message,
});
setMessage("");
};

return (
<CompactView title="Send to chat">
<TextField
label="Message"
value={message}
onChange={setMessage}
/>
{error && <Text content={error} variant="muted" />}
<Button
label={isLoading ? "Sending..." : "Send"}
onClick={handleSend}
disabled={isLoading || !message.trim()}
/>
</CompactView>
);
}

Lumio.render(<ChatPanel />, { target: "editor" });

Example: Switch OBS scene​

import { Button, Dropdown, useLumioAction } from "@zaflun/lumio-sdk";
import { useState } from "react";

function SceneSwitcher() {
const { execute: setScene, isLoading } = useLumioAction("obs:set_scene");
const [scene, setSceneValue] = useState("Main");

return (
<>
<Dropdown
label="Scene"
value={scene}
options={[
{ value: "Main", label: "Main" },
{ value: "BRB", label: "Be Right Back" },
{ value: "Ending", label: "Ending screen" },
]}
onChange={setSceneValue}
/>
<Button
label="Switch scene"
onClick={() => setScene({ scene_name: scene })}
disabled={isLoading}
/>
</>
);
}

Declaring permissions​

Actions require declaring the corresponding permission in lumio.config.json. Undeclared permissions are rejected at runtime:

{
"permissions": ["chat:send", "obs:set_scene"]
}

Declared permissions are shown to the user during installation, and they must grant consent before the extension can use them.

Notes​

  • Actions run from the editor surface and from layer surfaces in overlays and standalone widgets (see the table above). There is no viewer surface
  • useLumioAction() calls are not written to the audit log, except successful chat moderation (account:extension_moderation, see above)
  • The error property contains a human-readable message when an action fails (e.g., OBS is not connected, or the chat bot is not a moderator)
  • Spotify actions appear in the account's event log as spotify:* events with source: "extension"