Interactive Page
The interactive surface renders on a standalone web page at /ext/\{slug\} where viewers can interact with your extension — voting, playing games, submitting requests, or anything that requires direct audience participation.
Entry point
Every extension that includes the "interactive" target must have a src/interactive.tsx file:
// src/interactive.tsx
import { Lumio, CompactView, Button, Text, VStack, useExtensionStorage, useMutation, useQuery } from "@zaflun/lumio-sdk";
function VotingPage() {
const [storage] = useExtensionStorage();
const { data: results } = useQuery("getVoteResults");
const { mutate: vote, isLoading } = useMutation("castVote");
const total = (results?.yes ?? 0) + (results?.no ?? 0);
return (
<CompactView title={storage.topic ?? "Cast your vote"}>
<VStack>
<Text
content={`${total} votes so far`}
variant="muted"
/>
<Button
label={`Yes (${results?.yes ?? 0})`}
onClick={() => vote({ choice: "yes" })}
disabled={isLoading}
/>
<Button
label={`No (${results?.no ?? 0})`}
onClick={() => vote({ choice: "no" })}
disabled={isLoading}
/>
</VStack>
</CompactView>
);
}
Lumio.render(<VotingPage />, { target: "interactive" });
Authentication
Interactive pages use short-lived token authentication. The URL format is:
https://lumio.vision/ext/{slug}?token=lm_ext_xxxxxxxxxxxx
- Tokens are 15 minutes short-lived and scoped to the specific extension installation
- The token grants read access to the installation's storage and write access to permitted server mutations
- Tokens are generated by the Lumio host and distributed to viewers (e.g., via a bot command configured in the editor)
- No cookies or session storage are used — the token is the only credential
Full interactivity
Unlike the layer surface, the interactive surface has full component interactivity. All input components work as expected:
| Component | Interactive behavior |
|---|---|
Button | Clickable, triggers onClick |
Toggle | Toggleable, triggers onChange |
TextField | Editable text input |
TextArea | Editable multi-line input |
NumberField | Editable number input |
Dropdown | Selectable options |
Slider | Draggable range input |
Use cases
| Use case | Example |
|---|---|
| Voting | Viewers vote on which game challenge to attempt next |
| Predictions | Audience predicts the outcome of a game event |
| Song requests | Viewers submit song requests for the streamer |
| Chat games | Trivia, bingo, word games driven by viewer input |
| Challenge suggestions | Community submits ideas for the streamer |
| Polls | Quick one-question audience polls |
Sharing the link
The interactive page URL is available in the extension dashboard under the installation settings. To automatically share it in chat, request the chat:send permission and use useLumioAction("chat:send") in the editor:
{
"permissions": ["chat:send"]
}
Real-time updates
The interactive page receives storage updates in real time via WebSocket, just like the layer surface. If the editor changes the voting topic, the interactive page updates immediately for all viewers already on the page:
function VotingPage() {
const [storage] = useExtensionStorage();
// storage.topic updates in real time when the editor changes it
return (
<CompactView title={storage.topic ?? "Vote now"}>
...
</CompactView>
);
}
No OBS dependency
The interactive page works independently of any OBS Browser Source. Viewers access it directly in their browser — it does not require OBS to be open or the stream to be live.