Watch YouTube together
An example where everyone in the chat room watches a YouTube video picked by a moderator or higher.
Last updated October 19, 2026
When a moderator or higher enters a YouTube URL, the same video appears for everyone in the chat room. The video ID is sent over a channel and saved, so people who join later also see the current video.
Code
Put the code below on your page as is and it works. The first line is a pre-registration snippet that attaches events before uchat.js loads (Async loading and multiple chat rooms).
<script>U=window.U=window.U||{},U.events=U.events||[],U.chat=function(n){return{on:function(e,t){U.events.push([n,e,t])},off:function(e){for(var t=U.events.length;t>0;)U.events[--t][0]==n&&U.events[t][1]==e&&U.events.splice(t,1)}}};</script>
<script async src="https://client.uchat.io/uchat.js"></script>
<u-chat room="my-room" style="display:inline-block;width:100%;max-width:400px;height:500px"></u-chat>
<script>
U.chat('my-room').on('after.create#youtube-demo', function (room) {
var ui = room.skin;
var channel = room.plugin.add('youtube-demo');
var removeOverlay = null;
function show(id) {
if (removeOverlay) removeOverlay();
removeOverlay = null;
if (!id) return;
removeOverlay = ui.mount.overlay({
id: 'youtube-demo.player',
layer: 'content-overlay',
scope: 'message-list',
mount: function (host) {
host.style.pointerEvents = 'none'; // Let clicks on empty space reach the chat below
var frame = host.ownerDocument.createElement('iframe');
frame.src = 'https://www.youtube-nocookie.com/embed/' + id + '?autoplay=1';
frame.allow = 'autoplay; encrypted-media';
frame.style.cssText =
'position:absolute;top:8px;right:8px;width:320px;height:180px;border:0;pointer-events:auto';
host.appendChild(frame);
return function () {
frame.remove();
};
},
});
}
function videoId(text) {
var m =
/(?:youtu\.be\/|v=|embed\/|shorts\/)([A-Za-z0-9_-]{11})/.exec(text) ||
/^([A-Za-z0-9_-]{11})$/.exec(text);
return m ? m[1] : '';
}
// Receive: only from moderators or higher, or from the server (saved value, server API)
channel.onReceived(function (room, data) {
if (!data.user || data.user.auth < 2) return;
var id = String(data.data[0] || '');
if (id === '' || /^[A-Za-z0-9_-]{11}$/.test(id)) show(id);
});
ui.menu.add({
id: 'youtube-demo.open',
label: 'YouTube',
condition: function (ctx) {
return ctx.room.my.auth >= 2;
},
onSelect: function () {
ui.dialog.prompt('YouTube', 'Enter a video URL. Leave it empty to close.').then(function (text) {
if (text === null) return; // Canceled
text = text.trim();
var id = videoId(text);
if (text && !id) return ui.dialog.alert('YouTube', 'Not a valid YouTube URL.');
if (id) {
channel.save([id]); // Save for people who join later
channel.send([id]); // To everyone here now (it comes back to me too)
} else {
channel.clear();
channel.send(['']);
}
});
},
});
});
// Recalculate the button's display condition on join or when permissions change
function refreshMenu(room) {
room.skin.menu.resolver.refresh();
}
U.chat('my-room').on('after.join#youtube-demo', refreshMenu);
U.chat('my-room').on('after.user.modi#youtube-demo', refreshMenu);
</script>
Usage
- Moderators and higher see a YouTube button in the input toolbar. If your chat room doesn't use member integration, become an admin with
/login adminpasswordto try it. - Enter a URL and a player appears at the top right of the chat area. Enter an empty value and it closes for everyone.
- People who join later receive the saved value on join and see the same video.
How it works
| Step | API used | Description |
|---|---|---|
| Button | room.skin.menu.add |
condition shows it only to moderators and higher. Callbacks must be synchronous |
| Input | room.skin.dialog.prompt |
A Promise that returns the entered text on OK, or null on cancel |
| Send | channel.send, channel.save |
send goes to everyone connected now (including you); save stores it for people who join later |
| Display | room.skin.mount.overlay |
Attaches an area overlaid on the message list, and detaches it with the returned function |
The server sends the saved value with permission 4 on join, so it passes the receiver's permission check. For details on each API, see Skin UI API and Channel API and limits.
Play from the server
Send a video ID to the same channel with the Server REST API and you can play it from places like your site's admin screen. Data sent by the server has permission 4, so it passes the permission check in the code above.
curl -X POST https://api.uchat.io/v2/rooms/room_xxxxxxxxxxxxxxxx/events \
-H "Authorization: Bearer uchat_..." \
-H "Content-Type: application/json" \
-d '{"plugin":"youtube-demo","save":true,"data":["dQw4w9WgXcQ"]}'
If you send with "save": true, the value is saved in the chat room, so people who join later see the same video. It is saved even if you send it when no one is in the chat room. To close the video, save "data":[""]. Issue the API key in the API menu of the admin page.
Things to note
- Anyone can send data to the same channel. Always check the sender's permission (
data.user.auth) and the shape of the data you receive. - So the overlay doesn't block the chat, let clicks pass through the host and give
pointer-events:autoonly to the player. - Only moderators and higher can use
save. A free chat room can save to only one channel, so saving to another channel deletes the existing saved value. - Free chat rooms have a limit on channel traffic. A send to everyone counts once per connected user, and going over gives error
428(Channel API and limits).
Still not sure how it works? Ask your question on the contact board.