# U.chat() and the room object

> U.chat(), the entry point for page scripts, and the values and functions of the room object that event callbacks receive.

A page script picks a chat room with `U.chat()` and receives the `room` object as the first argument of event callbacks. This page is the authoritative list for both. For event names and `data`, see [Events](/en/doc/3.3); for channels (`room.plugin`), see [Channel API and limits](/en/doc/3.5); for the skin UI (`room.skin`), see [Skin UI API](/en/doc/3.4).

## U.chat() {#u-chat}

| Call | Returns |
| --- | --- |
| `U.chat('my-room')` — room not installed yet | Registrar `{ on, off }` |
| `U.chat('my-room')` — installed room | That room's `room` object (including `on`, `off`) |
| `U.chat('*')` | Registrar for all rooms `{ on, off }` |

Either way, you can attach events with `.on(name, callback)`.

```js
U.chat('my-room').on('after.join', function (room, data) {
	room.print('Welcome, ' + data.my.nick + '.');
});
```

- `U` is created by uchat.js. Because uchat.js loads with `async`, code that runs before it needs the pre-registration snippet. See [Async loading and multiple chat rooms](/en/doc/2.2).
- While the entry check (bot check) screen is shown, `U.chat('my-room')` may return `undefined`. Put code that runs right after page load inside the pre-registration snippet.

## on / off {#on-off}

| Function | Arguments | Description |
| --- | --- | --- |
| `on(name, fn)` | Event name (`name#tag` allowed), `fn(room, data)` | Registers a callback. For `after.create`, if the room is already ready, it is called once immediately |
| `off(name)` | `'name'`, `'#tag'`, `'name#tag'` | Removes matching registrations |

| `off` argument | Removes |
| --- | --- |
| `'after.message'` | All registrations for that event (with or without a tag) |
| `'#stats'` | All registrations tagged `stats` |
| `'after.message#stats'` | Only registrations with exactly that name |

- `U.chat('*').off(...)` also removes per-room registrations made with `U.chat('my-room')` or `room.on`. Use a unique tag so you do not remove other scripts' registrations.
- `U.chat('my-room').off(...)` and `room.off(...)` remove only registrations made on that room. `'*'` registrations remain.
- Do not call `off()` with no arguments. It throws an error if there are registrations to remove.
- Callbacks for the same event are called in the order they were registered. An exception in a callback is logged to the console, and the next callback is still called.

## room values {#properties}

| Name | Type | Description |
| --- | --- | --- |
| `room.id` | String | Chat room ID |
| `room.my` | [User object](#user-object) | Your own info. Empty object before entering (`after.join`) |
| `room.info` | Object | Chat room info. Empty object before entering. See [room.info](#room-info) below |
| `room.user` | `{ list, get }` | Connected users. See [room.user](#room-user) below |
| `room.setting` | `{ get, set, save, data }` | User settings stored in this browser. See [room.setting](#room-setting) below |
| `room.plugin` | Object | Channels. [Channel API and limits](/en/doc/3.5) |
| `room.action` | Object | Sending and commands. See [room.action](#room-action) below |
| `room.skin` | Object | Skin UI API. [Skin UI API](/en/doc/3.4) |
| `room.skin.arguments` | Object | Admin page skin settings merged with the `skin_arguments` attribute |
| `room.agent` | `{ userAgent, charset, mobile, android, ios, webkit }` | Browser info. `userAgent` is lowercase; `webkit` is a version number or `false` |
| `room.language` | `{ system, error }` | Notice and error strings for the current language. Error strings are `room.language.error[code]` |
| `room.locale` | String | The resolved UI language code (`ko`, `en`, `ja`). Empty string before the language pack loads |

## User object {#user-object}

`room.my`, `room.user.get()`, event `data.user`, and so on all have the same shape.

| Key | Type | Description |
| --- | --- | --- |
| `nick` | String | Nickname |
| `id` | String | Member ID (member integration). Empty if none |
| `level` | Number/String | Level (member integration) |
| `auth` | Number | `0` guest, `1` member, `2` moderator, `3` admin, `4` server (sent via REST API or a saved channel value; `nick` and similar fields are empty in this case) |
| `icons` | String | List of icon URLs (the `icons` value from member integration) |
| `nickcon` | String | Image URL shown instead of the nickname |
| `connected` | String | Entry time `'YYYY-MM-DD HH:MM:SS'` (in the viewer's time zone) |
| `time` | Number | Entry time (Unix seconds) |
| `mute` | `0`/`1` | `1` while muted |
| `session` | String | Session identifier (hex). Used as the basis for ignoring and granting permissions |
| `profileimg` | String | Profile image URL (only when present) |

## room.info {#room-info}

| Key | Description |
| --- | --- |
| `id`, `name` | Chat room ID and name |
| `mode` | `0` normal, `1` private channel, `4` channel chat room |
| `created` | Creation time `'YYYY-MM-DD HH:MM:SS'` |
| `frozen` | `1` if the room was frozen when you entered. It does not change when the room is frozen or unfrozen, so check with `system` events (`frozen`, `unfrozen`) |
| `whisper`, `call`, `individual`, `font` | Whether whisper, call, private channel, and font styling are enabled (`0`/`1`) |
| `userLinkage` | `1` if member integration is on |
| `slowSeconds` | Slow mode interval (seconds). `0` when off |

When chat room settings change, only the changed keys are merged into `room.info`, and an `update` event is fired.

## room.user {#room-user}

| Name | Description |
| --- | --- |
| `room.user.get(nick)` | Finds a user object by nickname. `undefined` if not found |
| `room.user.list` | Currently connected users. It is an object, not an array, and the keys are `escape(nickname)` |

```js
var user = room.user.get('홍길동');
if (user && user.auth >= 2) room.print('This user is a moderator or admin.');
```

- Use `user.get` to look up by nickname. The keys of `user.list` are encoded with `escape()`, so a Korean nickname used as-is will not be found.
- `user.get` may also return users who are not currently connected, such as people you saw in messages. Check `user.list` to see whether someone is connected.
- `user.list` changes only when join and leave notifications (`user.join`, `user.quit`) arrive. In rooms where the user list is open in the default skin or where 100 or more people are connected, these notifications do not arrive, so `user.list` may stay frozen at how it looked when you entered. → [Events](/en/doc/3.3#users)

## room functions {#functions}

| Function | Returns | Description |
| --- | --- | --- |
| `room.print(html)` | — | Shows a notice line as HTML on your screen only. Only elements that can run scripts are removed, so escape user input yourself. A `system` event (`type: 'notice'`) also fires |
| `room.on(name, fn)` | `room` | Registers an event for this room only. Same as [on / off](#on-off) |
| `room.off(name)` | — | Removes registrations for this room |
| `room.now()` | Number | Current time by the server clock (milliseconds, rounded to whole seconds) |
| `room.getTimeStamp([sec])` | String | Converts Unix seconds to `'YYYY-MM-DD HH:MM:SS'` (in the viewer's time zone). If omitted, uses the current server time |
| `room.reload()` | — | Removes the chat room and reinstalls it in the same place. Events registered on this room (`U.chat('my-room')`, `room.on`) are also removed, so you must register them again. `'*'` registrations remain |
| `room.disconnect()` | — | Disconnects. It is handled as if the connection dropped due to a network error, so it reconnects automatically |

## room.action {#room-action}

| Function | Returns | Description |
| --- | --- | --- |
| `send(message, style)` | `true`/`false` | Sends a message. `style` is `{ bold, italic, underline, color }` (all optional) |
| `slowRemaining()` | Milliseconds | Time left until you can send again under slow mode. `0` if you do not need to wait |
| `command(type, ...args)` | `false` if canceled in `before.command`, otherwise nothing | Runs a command. See [Commands](#commands) below |
| `plugin(type, args)` | `true`/`false` | Calls that channel's `addParser` callback, as if `!type args` had been typed in the chat box. For details, see [Channel API and limits](/en/doc/3.5#parser) |

```js
room.action.send('Hello');
room.action.send('Important!', { bold: true, color: '#e11d48' });
```

- `send` returns `false` if you are not connected, the message is empty, you must wait for slow mode, or `before.send` blocked it. `true` means it was sent to the server; if the server rejects it, an `error` event arrives.
- `color` accepts `#rgb`, `#rrggbb`, `rgb(r, g, b)`, and color names.
- For users who are not admins or moderators, the slow mode wait starts after sending.

## Commands {#commands}

The `type` in `room.action.command(type, ...args)` ignores case and `_` (`un_ignore` → `unignore`). Before connecting, it does nothing. If you lack permission or the arguments are wrong, an `error` event arrives.

Common commands:

| Command | Arguments | Permission | Description |
| --- | --- | --- | --- |
| `whisper` | Nickname, text | — | Whisper |
| `call` | Nickname | — | Call |
| `ignore`, `unignore` | Nickname | — | Ignore and unignore (stored in this browser) |
| `report` | Nickname, reason | — | Report |
| `changeinfo` | `{ nick: 'new nickname' }` | — | Change nickname |
| `password` | Password | — | Enter the entry password and rejoin |
| `chatlist` | Count (default 15, max 25) | — | Re-fetch past messages, plus whispers, calls, and invites addressed to you |
| `noticelist` | — | — | Fetch the chat room notices again (they arrive as the `system` event `notice`) |
| `individual` | — | — | Open your private channel in a new window |
| `invite` | Nickname | — | Invite that person to your private channel. Opens the private channel window first if it is not open |
| `popup` | — | — | Open this chat room in a new window (400×600) |
| `io` | `true`/`false` | — | Turn join and leave notifications on or off. When off, you receive only the user count (`user.count`) |
| `login` | Admin password | — | Become an admin. Not available in member integration rooms |
| `info` | Nickname | Moderator (anyone for themselves) | User info |
| `notice` | Text | Moderator | Post a notice |
| `mute` | Nickname, minutes, reason | Moderator | Mute. Up to 30 days (43200 minutes) |
| `unmute` | Nickname | Moderator | Unmute |
| `ban` | Nickname, reason, duration (seconds) | Moderator | Ban. Permanent if the duration is empty or 0 |
| `ip` | Nickname | Moderator | Check IP |
| `freeze`, `unfreeze` | — | Moderator | Freeze and unfreeze the chat room |
| `clearlog` | — | Moderator | Clear the chat (without permission, clears only your own screen) |
| `op`, `deop` | Nickname | Admin | Grant and revoke moderator rights |
| `logout` | — | Admin | Give up admin permissions |
| `adminpage` | — | Admin | Open the admin page in a new window |
| `upload` | Callback | — | Legacy skins only. Opens the upload window and receives the result as `callback(json)` |

```js
room.action.command('whisper', '홍길동', 'Do you have a moment to talk?');
room.action.command('changeinfo', { nick: 'NewNick' });
```

The server checks permissions again. Hiding a button in the UI does not by itself restrict a permission, and a command you lack permission for is rejected even if you send it.

## room.setting {#room-setting}

User settings stored only in this browser (localStorage). They share storage with the default skin's settings, so add a prefix to keys you create.

| Function | Description |
| --- | --- |
| `room.setting.get(key)` | Reads a value |
| `room.setting.set(key, value)` | Writes a value and saves immediately |
| `room.setting.save()` | Saves the current values |
| `room.setting.data` | The settings object itself |

```js
room.setting.set('myScript.muted', true);
room.setting.get('myScript.muted'); // true
```

In browsers where storage is unavailable (such as private browsing), values may be lost on reload.
