Bridge protocol
v0.js is a thin wrapper. If you prefer your own client — another framework, TypeScript types, a game engine compiled to WebAssembly — speak the protocol directly. It is JSON-RPC 2.0 over window.postMessage, the same transport as the MCP Apps standard.
Where the meeting is
ReMeet opens your page with two query parameters:
| Parameter | Value |
|---|---|
remeet_origin | The origin of the meeting page, for example https://remeet.video. Send messages only there and accept messages only from there. |
remeet_surface | panel or stage |
The meeting is window.parent.
Envelope
Every message is an object with remeet: 'v0' and jsonrpc: '2.0'.
Request from your app:
json
{ "remeet": "v0", "jsonrpc": "2.0", "id": 1, "method": "app.broadcast", "params": { "data": { "x": 3 } } }js
parent.postMessage(request, remeetOrigin);Response from the meeting — result or error:
json
{ "remeet": "v0", "jsonrpc": "2.0", "id": 1, "result": { "ok": true } }
{ "remeet": "v0", "jsonrpc": "2.0", "id": 2, "error": { "code": 403, "message": "Permission \"chat.send\" was not granted" } }Event from the meeting — no id, method is always event:
json
{ "remeet": "v0", "jsonrpc": "2.0", "method": "event", "params": { "name": "speaking", "data": { "ids": ["p_…"] } } }Check every incoming message: event.source === window.parent, event.origin === remeet_origin, remeet === 'v0'.
Methods
The first call must be ready; anything before it fails with 400.
| Method | Params | Result | Permission |
|---|---|---|---|
ready | { sdk: '0.1.0' } | the context object, see app.context | — |
participants.list | — | Participant[] | participants.read |
app.broadcast | { data } | { ok: true } | app.broadcast |
ui.notify | { text } | { ok: true } | — |
chat.send | { text } | { ok: true } | chat.send |
badges.set | { participant, text | null } | { ok: true } | badges.write |
stage.open | { everyone: boolean } | { ok: true } | stage.start when everyone |
stage.close | — | { ok: true } | — |
storage.get | { key } | { value } | storage |
storage.set | { key, value } | { ok: true } | storage |
storage.delete | { key } | { ok: true } | storage |
Events and their data are listed in SDK API → Events.
Minimal client
js
const query = new URLSearchParams(location.search);
const origin = query.get('remeet_origin');
const pending = new Map();
let seq = 0;
function call(method, params = {}) {
return new Promise((resolve, reject) => {
const id = ++seq;
pending.set(id, { resolve, reject });
parent.postMessage({ remeet: 'v0', jsonrpc: '2.0', id, method, params }, origin);
});
}
addEventListener('message', (event) => {
const message = event.data;
if (event.source !== parent || event.origin !== origin || message?.remeet !== 'v0') return;
if (message.id != null && pending.has(message.id)) {
const { resolve, reject } = pending.get(message.id);
pending.delete(message.id);
message.error ? reject(Object.assign(new Error(message.error.message), { code: message.error.code })) : resolve(message.result);
} else if (message.method === 'event') {
console.log('event', message.params.name, message.params.data);
}
});
const context = await call('ready', { sdk: '0.1.0' });