Channel API and limits
The canonical reference for room.plugin channels, which exchange real-time data, covering functions, value formats, and save and sending limits.
Last updated October 19, 2026
On this page
A channel (room.plugin) is a pathway for exchanging data other than chat messages in real time, between people in the same chat room or between your server and a chat room. This page is the canonical reference for functions, value formats, and limits. For the overall flow, see Sending and receiving real-time data; for sending from a server, see Server REST API.
room.plugin
| Name | Description |
|---|---|
room.plugin.add(channel) |
Returns a channel object. Calling it again with the same name returns the same object |
room.plugin.TO_ALL |
0. If the type of received data is this value, it was sent to everyone |
room.plugin.ONLY_ME |
1. If the type of received data is this value, it was sent to you only |
Choose channel names that do not collide within the chat room. To use saving (save), the name must start with a letter or digit, contain only letters, digits, _, and -, and be 64 characters or fewer.
U.chat('*').on('after.create#dice', function (room) {
if (room.id !== 'my-room') return;
var ch = room.plugin.add('dice');
ch.onReceived(function (room, data) {
room.print(data.user.nick + ' rolled: ' + data.data[0]);
});
ch.addParser(function (args) {
ch.send([Math.floor(Math.random() * 6) + 1]);
});
});
Channel object
| Function | Arguments | Description |
|---|---|---|
send(values) |
Value array | Sends to everyone in the chat room. You, the sender, receive it too |
sendTo(nick, values) |
Nickname, value array | Sends to one person only. You do not receive it unless you target your own nickname. If the target does not exist, nothing happens (no error) |
save(values) |
Value array | Saves the latest state on the server. Moderator or higher. See Saving below |
clear() |
— | Clears this channel's saved value. Moderator or higher |
onReceived(fn) |
fn(room, data) |
Adds a receive callback. See Receiving below |
addParser(fn) |
fn(args) |
Adds a callback that handles !channelname args input. See Command input handling below |
destroy() |
— | Removes the channel from the list. Registered callbacks are discarded too |
- The functions have no return value. Calls made before connecting are not sent. If the server rejects a call, an
errorevent fires (permission 402, value error 101, limit 428). - Callbacks added with
onReceivedandaddParsercannot be removed individually. Becauseaddreturns the same object, callbacks get mixed if your channel name collides with another script's. Use a unique name.
Value formats
Values you send are an array, and only the formats below are passed through as-is in each slot.
| Value sent | Value received |
|---|---|
| String | String |
| Integer 0 or greater | Number |
| Negative number, decimal | Number |
true, false |
true, false |
undefined |
undefined (empty slot) |
Object, array, null, function |
Dropped. The following values shift forward by one slot |
For structured data, split it across slots or put it in a single string slot with JSON.stringify. Wrap JSON.parse of a received string in try.
ch.send(['move', 3, 5]); // split across slots
ch.send(['state', JSON.stringify({ x: 3, y: 5 })]); // one string slot
Receiving
The onReceived callback receives (room, data).
| Key | Description |
|---|---|
data.user |
The sender's user object |
data.type |
0 (TO_ALL, send) or 1 (ONLY_ME, sendTo, targeted sends from the server, saved values) |
data.data |
Value array |
- Sent by the server: Data sent through the REST API and saved values received again on join have
data.user.authset to4and an empty nickname. Check whether data came from the server only withdata.user.auth === 4. - Saved values also arrive with
auth4, soauth4 alone does not prove the REST API sent it. Only moderators or higher can write saved values. - Anyone can send other data. Do not trust it based on the nickname alone; validate the format and range of the values.
- If
before.pluginreturnsfalse,onReceivedcallbacks are not called (Events).
Command input handling
In the default skin, when someone types !channelname arg1 arg2 in the chat input, that channel's addParser callbacks are called with (['arg1', 'arg2']). Arguments are strings split on spaces. You can trigger the same handling from code with room.action.plugin('channelname', ['arg1']).
| Case | Result |
|---|---|
| No channel with that name | room.action.plugin() returns false. The default skin sends the input as a normal message |
before.plugin returns false |
false. Callbacks are not called |
A callback returns false |
false. Later callbacks are not called, and the default skin sends the input as a normal message |
| Otherwise | true. The input is not sent as a message |
Parsers run only in your own browser. To let others know, call send inside the callback.
Saving
save(values) keeps the channel's latest state on the server. People who join later receive the saved value when they join (type 1, auth 4). It is not sent to people currently connected, so call send as well if needed.
| Item | Limit |
|---|---|
| Who can write | Moderator or higher (otherwise error 402) |
| Saved value per channel | Free rooms 1KB, paid rooms 4KB |
| Saved values for the whole room | 60KB |
| Number of channels in a free room | Effectively one. Saving to another channel clears the saved values of existing channels |
| Value formats | Strings, numbers, booleans |
- The size of one channel is the number of UTF-8 bytes of the value array encoded as JSON. The 60KB total is the size of the entire
{ channel: value array }object, including channel names, encoded as JSON. If a limit is exceeded or the channel name does not follow the rules, the request is rejected with error 101. - In a free room, when the saved value is replaced by another channel's, the person who saved gets a
controlevent (type: 'pluginDataReplaced'). - Values saved with
savelive only in the chat server's memory. They may be lost when the chat room closes or the server restarts, and they are deleted when a paid room becomes free. - If you save from your server with
"save": truein the Server REST API, the value is also kept on uchat servers, so it is read again the next time the chat room opens, even after the chat room closes or the server restarts. In this case it is also sent to people connected now, and the limits are the same as in the table above. Use this for values that must last (live status, scores, goal amounts, and so on).
Sending limits
| Limit | Details |
|---|---|
| Free room channel sending | The total number of recipients over the last 60 seconds cannot exceed 100. Exceeding it gives error 428 |
| Paid rooms | No channel sending limit |
| Packet count | When packets sent from the same IP per second (messages, commands, and channel sends combined) reach 10, you get error 425; going further disconnects you |
Recipients are counted like this.
| Send | Deducted |
|---|---|
send, REST API send to everyone |
Number of connected users at the time |
sendTo, REST API targeted send |
1 |
- Deducted amounts come back after 60 seconds. For example, in a free room with 20 connected users, you can
sendup to 5 times per minute. sendandsendTofrom page scripts share the same limit with REST API sends.- In a free room that has hit the limit,
saveis also rejected with error 428.
For state that changes often (positions, timers), do not send every time; batch updates, or send only when something changes.
Still not sure how it works? Ask your question on the contact board.