Send Live Updates to Other Users


KV sharing is in beta. Method shapes, limits, and behavior may change between releases.

A scoreboard app keeps the score of a game in the scorekeeper's Puter account. Fans want to see each change as it happens. With a watch share, another Puter user gets an event each time a key under a prefix changes, with the new value in it. They can't read or change the keys in any other way.

You want to… Use
Send changes to people you pick, as they happen A watch share, as in this recipe
Let them load the current data at any time too A read share, as in When Fans Need to Catch Up
Show data to anyone, signed in or not Hosting or a worker. A share is for one Puter user.

Share the Game

Keep each game under its own prefix, and share it with puter.kv.share() at 'watch' access. Your app first asks the user once for permission to share the game: prefix with puter.perms.request():

const prefix = `game:${crypto.randomUUID()}:`;
await puter.kv.set(`${prefix}score`, { home: 0, away: 0 });

await puter.perms.request('kvShare', { prefix: 'game:', access: 'watch' });

const share = await puter.kv.share({
    prefix,
    recipient: 'alice',
    access: 'watch',
    label: 'Lions vs Bears',
});

Share with each fan the same way. Every fan is a separate share.

Update the Score

The scorekeeper writes the score like any other key. Each write sends an event to every fan:

await puter.kv.set(`${prefix}score`, { home: 1, away: 0 });

Watch as a Fan

The fan finds the share with puter.kv.listShared() and subscribes to kv:<handle>:* with puter.events.onLocal(). Pass includeValue: true to get the new value with each event:

const { items } = await puter.kv.listShared();
const { handle, label } = items[0];

await puter.events.onLocal(`kv:${handle}:*`, ({ event }) => {
    if (event.op === 'set') showScore(label, event.value);
}, { includeValue: true });

The key in each event is relative to the shared prefix, so it's score here. Writes to the same key within 250 ms arrive as one event with the latest value. A fan who follows several games has one share for each, and subscribes to each one the same way.

When Fans Need to Catch Up

A watch share sends changes and nothing else. A fan who opens your app between two changes sees nothing until the next one. When the connection drops, the fan gets an event with op: 'gap' for the changes they missed, and has no way to read the current score.

If fans need to catch up, share with read access instead. Sharing the same prefix with the same person again changes their access and keeps the handle:

await puter.kv.share(prefix, 'alice', 'read');

Your app then needs permission at read level too, so request access: 'read' in the first step. With read access, the fan loads the score when the app opens and again after a gap:

const showLatest = async () => showScore(label, await puter.kv.get('score', { handle }));

await showLatest();
await puter.events.onLocal(`kv:${handle}:*`, async ({ event }) => {
    if (event.op === 'gap') return showLatest();
    if (event.op === 'set') showScore(label, event.value);
}, { includeValue: true });

Limits

Rate Limits and Quotas has the numbers for each of these.

← All recipes