On this page
Miniup Live recipes
Getting started
Open Create an interactive app, choose an app and enter a name. Create App publishes and configures Live in one operation. Ready to use means publication and matching Live settings were confirmed. Open the app, start a room and invite a friend.
Live remains in a controlled rollout. An address must be eligible before a new app can be activated. Exploring the Gallery or downloading a starter does not enable Live. If publication succeeds but activation fails, use Finish Setup; it keeps the existing page. After an interrupted request, Check setup recovers the original operation. Reuse that operation rather than creating another app to work around a timeout.
Official Live Gallery demos offer Open and Create Your Own. Creating your own uses a clean official template. It copies no demo rooms, votes, notes, guest identities, secrets or private data. Sign-in preserves your selection.
The five recipes below target SDK 1.3.0, compatible with the stable /api/live/v1/ API. They are ordinary HTML/CSS/JavaScript projects. Download a ZIP, edit the files, and publish through Miniup’s existing ZIP/project workflow. No npm, Node.js, React or build step is required in an app. The SDK needs a published Miniup origin with matching Live settings; opening the files directly from disk cannot authorize a room.
Built-in components
For a complete game, prefer Chess. Whiteboard and Poll also provide their complete synchronized interfaces. Selecting a mode does not implement a custom application’s behavior.
<miniup-chess multiplayer></miniup-chess>
<script type="module" src="/api/live/v1/components.js"></script>The built-in app’s Invite, Chat and Leave controls use the same room. When chat is disabled, Room opens participant and host controls. A separate floating button stays off the board/canvas while these inline controls are available.
Inline room controls
The workspace recipes include Room & chat, opening the platform panel for chat, participants and host controls. Their invitation form stays visible when a friend opens a room link. A custom app with its own joining UI can provide a button marked data-miniup-live-controls; after connecting, dispatch miniup-live-controls when the button becomes visible. This explicitly declares that the app supplies its own joining UI. The injected overlay hides the floating trigger, keeps the invitation form clear, and returns keyboard focus to the visible button when closed. Clicking it opens the existing panel:
button.addEventListener('click', async () => {
await import('/api/live/v1/overlay.js');
window.dispatchEvent(new CustomEvent('miniup-live-open'));
});The marker controls presentation only. Room and site permissions are still enforced on the server. Without this explicit integration, the normal floating Live interface remains available.
Shared state
import { live } from '/api/live/v1/sdk.js';
const room = await live.connect({ nickname: 'Alex' });
const stop = room.on('state', snapshot => {
render(room.get('count', 0));
});
await room.increment('count');increment(key, by = 1) is a trusted atomic integer action for a custom Shared Workspace. It accepts whole-number changes from -1000 to 1000, excluding zero, with values bounded to ±1,000,000,000 and at most 64 counter keys. After a key becomes an atomic counter, set() cannot replace it. It remains correct when participants click simultaneously. Do not implement a shared counter with room.set('count', room.get('count') + 1).
room.set(key,value) remains available for a persistent custom value with room-revision conflict checks. It is not an atomic read-modify-write operation. get(key,fallback) returns a copy of the latest received value. Acknowledgment confirms acceptance; the following state update supplies the rendered authoritative snapshot.
Custom events
const stop = room.on('app:highlight', value => showHighlight(value));
room.emit('app:highlight', { item: 'north' });Transient events are small, throttled, best-effort messages. They are not restored after refresh. Use them for previews or pointers, not votes, saved notes, counters or authoritative game moves. Presence/chat alone does not synchronize application content.
Collaborative objects
const scope = new AbortController();
room.watchObject('note-one', object => {
showSavedNote(object?.deleted ? null : object?.value);
}, { signal: scope.signal });
await room.createObject('note-one', { text: 'First draft' });
// When opening an editor after the saved object arrives:
function openEditor() {
const object = room.getObject('note-one');
return { draft: structuredClone(object.value), baseVersion: object.version };
}
// Pass the version captured by openEditor, not a newer background update.
async function saveEditor(editor) {
await room.updateObject('note-one', editor.draft, editor.baseVersion);
}
async function deleteFromEditor(editor) {
await room.removeObject('note-one', editor.baseVersion);
}
scope.abort(); // Removes subscriptions, including queued initial callbacks.The calls above illustrate separate operations; after each accepted change, wait for the new object version before performing the next edit. For an editor, capture the version when loading the draft. Do not update that baseline just because another participant saved while the user was typing.
getObject(key) returns a copy of {version,value,deleted,author?,access?} or null. watchObject calls back initially and when that object’s version changes, including deletion. Independent object edits can proceed concurrently; changes to the same object require its exact expected version. Deleted objects retain versioned tombstones. A room holds at most 256 object keys, including tombstones, within the existing 256 KiB total room-state limit. The starters stop normal additions once 50 visible items are present; simultaneous additions can cross that UI threshold. The server enforces the 256-key and total-state limits. Start a new room for a fresh document budget.
On object_conflict, keep the draft and wait for the requested authoritative snapshot. The recipes offer Review latest without erasing the draft. Use latest loads the saved version; Keep my draft explicitly adopts the reviewed version as the next save baseline. Another intervening edit can still cause a conflict. No helper automatically overwrites another person’s work or silently retries a stale edit.
Shared objects are editable by room participants by default. createObject(key,value,{access:'author'}) gives the creator and room host editing/removal permission. The server records the author and preserves this policy through updates and tombstones. A browser cannot transfer ownership or downgrade it to shared access. These are room permissions; site authentication still applies.
Trusted actions
room.action(name,payload) submits only implemented platform rules: Chess moves/resignation/rematch, whiteboard strokes/host clear, poll questions/votes/closure, and documented room/workspace actions. The platform does not execute supplied JavaScript, custom validators or arbitrary game rules.
The SDK retains the original action ID and serialized payload during reconnect retries. A normal conflict does not create a replacement action. If an action times out with outcome_unknown, the SDK requests a snapshot and blocks new actions until authoritative state is recovered. Inspect that state before deciding whether another user action is needed. Never blindly repeat a move, vote or increment as a new action after an uncertain result.
Use room.on('connection',callback) for connection status. It immediately supplies the current status and reports reconnects. All on/watchObject subscriptions return an unsubscribe function and support {signal}. disconnect() removes subscriptions, timers and lifecycle listeners. Refresh/reconnect restores the existing participant identity and authoritative state when the browser’s site session is retained.
Examples
Each source link returns copyable text. Each ZIP contains the complete starter, its shared modules/styles and any required vendored library files. The HTML download alone uses the official versioned recipe assets.
Counter
Required settings: Live enabled, Shared Workspace, no built-in component. Guests are allowed when your site policy permits them.
Create Counter · HTML · Complete ZIP · HTML source · JavaScript source
The counter shows actual shared state and applies every accepted increment on the server. Spectators cannot change it. No client supplies trusted server code.
import { $, roomUI, task } from './shared.js';
roomUI((room, signal) => {
room.on('state', () => {
$('#value').textContent = String(room.get('count', 0));
}, { signal });
$('#increment').onclick = () =>
task($('#increment'), () => room.increment('count'));
});Checklist
Required settings: Live enabled, Shared Workspace, no component.
Create Checklist · HTML · Complete ZIP · Source · Object editor source
Add, complete, reopen, edit and remove tasks. Every item has its own stable key and version. Two people can add different items at once; conflicting changes to one item require review. All room participants can edit shared tasks, while spectators are read-only. Render task text with textContent.
Notes
Required settings: Live enabled, Shared Workspace, no component.
Create Notes · HTML · Complete ZIP · Source · Object editor source
Notes are independent versioned objects, not CRDT/OT documents. People can edit different notes simultaneously. If two edit the same note, the draft is retained and the latest saved version can be reviewed before an explicit decision. Refresh restores saved notes; an unsaved local draft is not persisted. Keep sensitive information out of public guest rooms.
Map
Required settings: Live enabled, Shared Workspace, no component.
Create Map · HTML · Complete ZIP · Source
Add markers by tapping the map or entering coordinates. Move a permitted marker by dragging it or editing its coordinates; edit labels and remove markers from the list. The server enforces author/host access to marker objects. Share bounded marker operations, not the map renderer or images.
Leaflet 1.9.4 is vendored under its BSD license. The basemap uses attributed OpenStreetMap tiles , normal browser caching and a valid referrer. There is no tile prefetch or Miniup tile proxy. Tile access is best-effort; markers and coordinate controls still work when the basemap fails. For higher traffic, configure a suitable tile provider according to its terms. Never put private API keys in the browser. Marker labels use safe text nodes, not HTML.
Turn-based
Required settings: Live enabled, Turn-Based Game, Chess component.
Create Chess · Starter ZIP · Source
This starter uses the complete official Chess component. Rooms provide identity, ordering, reconnection and state recovery; Chess supplies the trusted game rules, seats and turns. Moves are validated on the server. A custom event containing a board move is not an authoritative game. Other games need another supported platform rules implementation; arbitrary user rules are not supported.
Agent discovery
Fetch /api/live/capabilities, then its recipes URL: /api/live/recipes/v1/manifest. Manifest version 1 references these five recipes, SDK compatibility, exact settings, trusted actions, source files, ZIPs, documentation and creator links. It contains no source blobs or credentials. runtimeReady=false means the new recipe capabilities have not been released; do not claim the counter action is operational based on deployed source alone.
Capability discovery preserves available and existing fields. sdkDeployed identifies distribution; activationInfo distinguishes platform rollout, site eligibility, owner activation and requested configuration. Use ?recipe=checklist or ?component=chess on a published site’s capability endpoint to check the requested experience. Anonymous protected-site discovery returns site_access_required with eligibility/activation/configuration set to null; it does not reveal private settings. Owner/admin permission-sensitive status uses the capability response’s ownerStatus link with the existing signed-in session. An invitation never replaces site access.
An agent creating a collaborative checklist should fetch the recipe, customize the complete static files, publish with the existing Miniup tools, return the actual URL and explain any remaining owner activation/rollout step. For multiplayer Chess, prefer the built-in component. “Publish my website live” means ordinary publication unless collaboration is requested. No new MCP tool is needed; existing MCP tools do not activate Live settings automatically. Existing publishing tools remain compatible.