lumio.config.json Reference
The manifest file at the root of every extension project. It defines the extension's identity, capabilities, and distribution settings.
Full reference
{
"$schema": "https://lumio.vision/schemas/lumio.config.schema.json",
"extensionId": "88b2478a-39c7-468e-bebd-14e52fd97ac0",
"name": "Sports Scoreboard",
"description": "Display live sports scores from ESPN on your stream overlay.",
"category": "widget",
"version": "1.2.0",
"targets": ["editor", "layer"],
"server": true,
"permissions": ["chat:send"],
"egress": {
"allowHosts": ["site.api.espn.com", "cdn.espn.com"],
"allowPorts": []
},
"fonts": ["Inter", "Roboto Mono"],
"visibility": "public",
"pricing": {
"type": "free"
},
"config_schema": {
"primaryColor": {
"type": "color",
"label": "Primary color",
"default": "#6366f1"
},
"fontSize": {
"type": "slider",
"label": "Font size",
"default": 16,
"min": 8,
"max": 72,
"unit": "px"
}
}
}
Fields
$schema
| Type | Required |
|---|---|
string | No |
URL to the JSON Schema file for editor validation and autocompletion in VS Code. Always use:
"$schema": "https://lumio.vision/schemas/lumio.config.schema.json"
This URL points to a live, dynamically generated JSON Schema served by the Lumio web app. It is NOT a static file — the schema is generated at runtime and reflects the current config format (including triggers, platforms, and config_schema fields).
The endpoint is CORS-open (Access-Control-Allow-Origin: *) so VS Code and other editors can fetch it for autocompletion and validation without authentication.
extensionId
| Type | Required |
|---|---|
string (UUID v4) | Yes |
The unique identifier assigned to your extension when it was created via lumio init or the dashboard. It must be a valid UUID that exists in the Lumio database.
"extensionId": "88b2478a-39c7-468e-bebd-14e52fd97ac0"
You cannot change this value after creation. The Extension-ID is how Lumio links your deployed bundle to your extension record.
name
| Type | Required | Max length |
|---|---|---|
string | Yes | 255 characters |
The display name shown in the extension store and dashboard. Use title case. Keep it concise and descriptive.
"name": "Sports Scoreboard"
description
| Type | Required | Max length |
|---|---|---|
string | Yes | 1000 characters |
A short description of what the extension does. Used in the store listing and dashboard. Plain text only — no Markdown.
"description": "Display live sports scores from ESPN on your stream overlay."
category
| Type | Required |
|---|---|
enum | Yes |
The extension's primary category. Used for store filtering and browsing.
| Value | Description |
|---|---|
"widget" | Standalone visual element (scoreboard, timer, now playing) |
"extension" | General-purpose extension that doesn't fit another category |
"overlay" | Full-screen transparent layer overlay |
"bot_module" | Chat bot command or moderation module |
"integration" | External service connector (Discord, StreamElements) |
"theme" | Visual style pack for overlays |
version
| Type | Required |
|---|---|
string (semver) | Yes |
Semantic version of the extension. Must follow MAJOR.MINOR.PATCH format.
"version": "1.2.0"
The version in lumio.config.json is the source of truth — lumio deploy reads it automatically. You can also override it with the -v flag.
targets
| Type | Required |
|---|---|
string[] | Conditional |
Which surfaces the extension renders on. At least one target is required for widget, overlay, extension, integration, and theme categories. Bot module extensions (category: "bot_module") have no visual surfaces and should omit this field or set it to an empty array.
"targets": ["editor", "layer"]
| Value | Surface |
|---|---|
"editor" | Dashboard sidebar panel |
"layer" | Browser Source overlay |
"interactive" | Standalone audience page |
"designer" | Fullpage designer overlay with split pane |
server
| Type | Required | Default |
|---|---|---|
boolean | No | false |
Enable server functions. When true, the server/ directory is bundled and deployed as server-side code.
"server": true
permissions
| Type | Required |
|---|---|
string[] | No |
Lumio service actions the extension needs. Shown to users at install time — users must grant consent. See Permissions for the full list.
"permissions": ["chat:send", "obs:set_scene"]
egress
| Type | Required |
|---|---|
object | No |
Outbound network allowlist for ctx.fetch() in server actions. See Egress.
"egress": {
"allowHosts": ["api.example.com", "*.example.com"],
"allowPorts": [8443]
}
fonts
| Type | Required |
|---|---|
string[] | No |
Google Fonts to preload for the extension. Font names must match the Google Fonts name exactly.
"fonts": ["Inter", "Roboto Mono", "Press Start 2P"]
sounds
| Type | Required | Default |
|---|---|---|
array | No | [] |
Declare audio files to bundle with the extension. Bundled sounds are added to the user's sound library on install and removed on uninstall. Users cannot delete or rename them.
"sounds": [
{ "file": "alert.mp3", "name": "Alert" },
{ "file": "chime.wav", "name": "Chime", "default_volume": 0.8 }
]
| Field | Type | Required | Description |
|---|---|---|---|
file | string | Yes | Relative path in dist/sounds/. 1-255 characters. |
name | string | Yes | Display name in the Sounds Panel. 1-255 characters. |
default_volume | number | No | Default playback volume (0.0-1.0). |
Supported formats: MP3, WAV, OGG, WebM, M4A, AAC, FLAC. Default limit: 50 sounds per extension (admin-configurable). Place audio files in dist/sounds/ before running lumio deploy.
visibility
| Type | Required | Default |
|---|---|---|
enum | No | "private" |
Controls who can see and install the extension.
| Value | Access |
|---|---|
"private" | Only the developer can see and install |
"unlisted" | Anyone with the direct link can install |
"public" | Listed in the extension store |
"paid" | Listed in the store, requires purchase (developer verification required) |
pricing
| Type | Required | Default |
|---|---|---|
object | No | { "type": "free" } |
Pricing configuration. See Pricing for details.
"pricing": { "type": "free" }
config_schema
| Type | Required |
|---|---|
object | No |
User-facing settings schema. Fields defined here appear in an auto-generated settings panel and are accessible via useLumioConfig().
"config_schema": {
"primaryColor": {
"type": "color",
"label": "Primary color",
"default": "#6366f1"
},
"showTimestamp": {
"type": "boolean",
"label": "Show timestamp",
"default": true
},
"maxItems": {
"type": "slider",
"label": "Maximum items to show",
"default": 5,
"min": 1,
"max": 50,
"step": 1
},
"font": {
"type": "font",
"label": "Display font",
"default": "Inter"
},
"displayOptions": {
"type": "group",
"label": "Display Options",
"collapsed": true,
"fields": {
"opacity": {
"type": "slider",
"label": "Opacity",
"default": 100,
"min": 0,
"max": 100,
"unit": "%"
}
}
}
}
Supported field types
| Type | Description | Key properties |
|---|---|---|
string | Single-line text input | placeholder |
number | Numeric input | min, max, step |
boolean | Toggle switch | |
color | Color picker with hex input | |
select | Dropdown with predefined options | options |
textarea | Multi-line text input | placeholder, rows |
slider | Range slider | min, max, step, unit |
font | Font family picker (Google Fonts) | |
icon | Icon picker (Lucide, emoji, emotes, uploads) | |
image | Image upload or URL | |
sound | Sound picker — selects a sound from the account's sound library. Value is a UUID (sound ID). SchemaEditor renders a dropdown picker. | |
multiselect | Multiple selection from options | options, multiple |
group | Collapsible group of nested fields | fields, collapsed |
divider | Visual separator (no value) | |
info | Read-only informational text (no value) | content |
channel | Multi-platform channel picker | |
designer | Fullpage designer surface field | presets |
Common field properties
Every field type supports:
| Property | Type | Description |
|---|---|---|
label | string | Display label (required for all types) |
default | varies | Default value |
required | boolean | Whether the field must have a value |
visible_when | object | Conditional visibility — show the field only when another field has a specific value |
Server-side validation
Config values are validated against your config_schema when users save settings — both through the dashboard and via the API. Invalid values are rejected with descriptive error messages.
| Check | Example |
|---|---|
| Type match | A number field rejects string values |
| Required fields | Fields with required: true must be present and non-null |
| Select options | select and multiselect fields only accept values from the declared options array |
| Color format | color fields must be valid #RRGGBB or #RRGGBBAA hex strings |
| Slider range | slider values must be within min/max bounds |
| Unknown keys | Keys not declared in config_schema are rejected |
Extensions can trust that ctx.config values match the declared types at runtime — the API enforces this before writing to the database.
The sound field type
A sound field lets users pick a sound from their account's sound library. The stored value is a UUID string (the sound ID) or null if no sound is selected. The SchemaEditor renders this as a dropdown populated with all sounds in the account's library, including extension-bundled sounds.
{
"config_schema": {
"alertSound": {
"type": "sound",
"label": "Alert sound",
"default": null
}
}
}
At runtime, ctx.config.alertSound holds the sound ID (UUID string) or null. Pass this ID to the useLumioSound hook to play the configured sound.
Auto-generated settings UI
Fields defined in config_schema are automatically rendered in a settings panel by the SchemaEditor component — no custom editor.tsx needed. Extensions can use config_schema alone, a custom editor.tsx alone, or both (schema fields render first, custom editor below).
designer_schema
| Type | Required |
|---|---|
array | No |
An array of field definitions for the fullpage designer surface. The designer provides a split-pane view with a live preview alongside configuration fields. Fields use the same type system as config_schema.
"designer_schema": [
{
"key": "layout",
"type": "select",
"label": "Layout",
"default": "horizontal",
"options": [
{ "value": "horizontal", "label": "Horizontal" },
{ "value": "vertical", "label": "Vertical" }
]
}
]
Unlike config_schema (which is an object keyed by field name), designer_schema is an array where each entry includes a key property.
platforms
| Type | Required |
|---|---|
string[] | Conditional |
Declares which chat platforms the extension supports. Required when category is "bot_module", ignored for other categories.
"platforms": ["twitch", "youtube", "kick"]
| Value | Platform |
|---|---|
"twitch" | Twitch IRC chat |
"youtube" | YouTube Live chat |
"kick" | Kick chat |
"trovo" | Trovo chat |
"discord" | Discord (bot modules only) |
Bots only match triggers for extensions that support their platform. A Twitch-only extension does not receive YouTube messages.
Discord is restricted to bot module extensions — widget, overlay, and theme extensions cannot target Discord.
triggers
| Type | Required |
|---|---|
object | No |
Defines when bot module handlers fire. Only allowed when category is "bot_module" — other categories with a triggers field are rejected at validation.
"triggers": {
"commands": [
{
"name": "points",
"description": "Show your points balance",
"cooldown_global": 5,
"cooldown_user": 10,
"min_role": "everyone"
}
],
"keywords": ["gg", "nice shot"],
"patterns": ["https?://clips\\.twitch\\.tv/\\S+"],
"events": ["twitch:subscribe", "twitch:raid"],
"timers": [
{
"name": "reminder",
"interval": 300,
"handler": "periodicReminder"
}
]
}
| Sub-field | Type | Description |
|---|---|---|
commands | array | Chat commands with prefix matching. Max 20. |
keywords | string[] | Substring matches. Min 3 chars each. Max 50. |
patterns | string[] | Regex patterns. Max 200 chars each. Max 10. |
events | string[] | Platform event types. |
timers | array | Recurring handlers. Min 60s interval. |
See Triggers for the full reference with validation rules and available event types.