이벤트

채팅방 이벤트의 이름, 받는 값, before에서 false를 돌려줄 때 실제로 막히는 것을 정리한 목록이에요.

마지막 수정 2026년 10월 20일

이 페이지

채팅방에서 일어나는 일을 U.chat(채팅방).on(이름, function (room, data) { ... })으로 받아요. 이 문서는 이벤트마다 언제 오는지, data에 무엇이 있는지, before.에서 false를 돌려주면 실제로 무엇이 막히는지를 코드 기준으로 정리해요. 등록·해제 방법은 U.chat()과 room 객체를 보세요.

규칙

  • 대부분의 이벤트는 before.이름과 after.이름 짝으로 와요. before.는 기본 처리 전에, after.는 처리 뒤에 와요.
  • 콜백은 (room, data)를 받아요. room은 room 객체이에요.
  • before. 콜백이 false를 정확히 돌려주면 그 뒤의 콜백은 불리지 않고, 아래 표의 "false를 돌려주면" 칸에 적힌 처리만 멈춰요. 이벤트마다 막히는 범위가 달라요.
  • before.에서 data의 값을 고치면 이어지는 처리(화면 표시, 전송)가 고친 값을 써요. 고칠 수 있는 이벤트는 표에 적었어요.
  • 막혀서 기본 처리가 멈추면 after.도 오지 않아요.

이벤트 목록

이벤트 언제 data before에서 false를 돌려주면
before.create 채팅방 설치를 시작함(설정·스킨을 받기 전). 다시 설치할 때마다 다시 옴 {} 막을 수 없어요(설치는 그대로 진행)
after.create 채팅방 화면 준비 완료(접속 전). 다시 설치(room.reload())할 때마다 다시 옴 { id } —
before.join 서버에 입장을 요청하기 직전. 다시 접속할 때마다 다시 옴 { user } 회원 연동이 아닌 방: 입장 요청을 보내지 않아요. 회원 연동 방: 아래 주의 참고
after.join 입장 완료, 내 정보를 받음. 다시 접속할 때마다 다시 옴 { my } (before 없음)
before.message, after.message 채팅 메시지 한 줄(지난 대화, 내 메시지 포함) 메시지 화면에 표시하지 않아요
before.whisper, after.whisper 귓속말(내가 보낸 귓속말의 확인 포함) 귓속말 화면에 표시하지 않아요
before.send, after.send 내가 메시지를 보낼 때(/명령, !명령 입력은 제외) { message, bold, italic, underline, color } 보내지 않아요. room.action.send()가 false를 돌려줘요
before.command, after.command 명령을 실행할 때 { type, data } 실행하지 않아요. room.action.command()가 false를 돌려줘요
before.plugin, after.plugin 채널 데이터를 받거나, !명령을 입력할 때 채널 받은 데이터: onReceived 콜백을 부르지 않아요. !명령: addParser 콜백을 부르지 않고 room.action.plugin()이 false를 돌려줘요
before.user.join, after.user.join 다른 사람이 들어옴. 오지 않는 경우는 사용자 변화 참고 { user } 화면에 입장 표시를 하지 않아요. room.user.list에는 이미 들어가 있어요
before.user.quit, after.user.quit 다른 사람이 나감 { user: { nick } } 화면에 퇴장 표시를 하지 않고 room.user.list에서도 지우지 않아요
before.user.modi, after.user.modi 누군가(나 포함)의 닉네임·권한·채팅금지가 바뀜 { target, changed } room.my, room.user.list, 화면에 반영하지 않아요. room.user.get()은 이미 새 값을 돌려줄 수 있어요. 쓰지 않는 것을 권해요
before.user.count, after.user.count 접속자 수만 바뀜(입장·퇴장 대신 오는 경우는 사용자 변화 참고) { count } 화면의 접속자 수를 바꾸지 않아요
before.update, after.update 채팅방 설정이 바뀜 바뀐 값 { 키: 값 } room.info와 화면에 반영하지 않아요
before.system, after.system 시스템 안내 줄(공지·차단·채팅금지·호출 등, room.print 포함) { type, data } 화면에 표시하지 않아요
before.control, after.control 서버 제어 신호(대화 청소, 투표 상태 등) { type, data } 스킨에 전달하지 않아요
before.error, after.error 오류(서버 오류와, 명령 인자 검사 같은 내 쪽 오류) { code } 화면에 오류를 표시하지 않아요
before.disconnect, after.disconnect 연결이 끊김(페이지를 떠나거나 태그를 지울 때는 오지 않음) {} 스킨에 알리지 않고, 네트워크 오류일 때의 자동 재접속도 하지 않아요

before.에서 막아도 서버에서 일어난 일은 그대로예요. 예를 들어 before.system으로 차단 안내를 숨겨도 차단은 적용되고, before.user.quit을 막아도 그 사람은 이미 나갔어요. 대부분 내 화면에 보이는 것만 바뀌어요.

일어나는 순서

채팅방이 열릴 때

  1. before.create — 설치 시작. room.info, room.my는 아직 비어 있어요.
  2. 채팅방 설정·언어·플러그인·스킨을 불러와요(플러그인 실행 파일이 여기서 실행됨).
  3. after.create — 스킨 화면 준비 완료. 스킨 UI와 채널은 여기서 등록해요.
  4. before.join → 서버에 입장 요청 → after.join.
  5. 지난 대화와 공지가 message, whisper, system 이벤트로 와요.

입장 확인(봇 검사) 화면이 뜨는 방은 확인을 통과한 뒤 1번부터 시작해요. 네트워크 문제로 다시 접속하면 4번부터 다시 와요.

내가 메시지를 보낼 때

  1. before.send → 서버로 전송 → after.send
  2. 서버가 채팅방 모두에게(나 포함) 메시지를 보내요.
  3. before.message → 화면에 표시 → after.message

after.send는 "서버로 보냈다"는 뜻일 뿐, 받아들여졌다는 뜻이 아니에요. 서버가 거절하면 메시지가 돌아오지 않고 error(권한 없음 410, 같은 내용 반복 430 등), system(muted, bad_word), control(slowWait) 이벤트가 대신 와요. 실제로 올라갔는지는 after.message로 확인하세요.

채팅창 입력이 /로 시작하면 send 대신 command, !로 시작하면 plugin 이벤트로 가요. 기본 스킨은 !명령을 처리할 채널이 없거나 막히면 그 입력을 일반 메시지로 보내요.

연결이 끊길 때

  1. before.disconnect → 스킨에 알림 → 자동 재접속 판단 → after.disconnect
  2. 네트워크 오류로 끊겼으면 다시 접속하고 before.join부터 다시 와요.

차단되었거나 서버가 오류를 보낸 직후 끊겼으면 다시 접속하지 않아요. 브라우저를 닫거나, 다른 페이지로 가거나, <u-chat> 태그를 지우거나, room.reload()할 때는 disconnect 이벤트가 오지 않아요. 떠나기 전에 할 일은 브라우저의 pagehide 이벤트에서 하세요.

입장

U.chat('my-room').on('after.join', function (room, data) {
	// data.my 는 room.my 와 같은 모양의 사용자 객체
	room.print(data.my.nick + '님, 환영합니다.');
});

before.create는 화면도 정보도 없는 시점이라 쓸 일이 드물어요. 막을 수 없고, 입장 정보를 바꾸려면 before.join을 써요.

before.join의 data.user:

방 data.user 고칠 수 있는 것
회원 연동이 아닌 방 { nick } — 이 브라우저에 저장된 닉네임(없으면 빈 값) data.user.nick을 바꾸면 그 닉네임으로 입장을 요청해요
회원 연동 방 user_data(또는 user_data_url)를 푼 값. user_data에 넣은 키와 time, hash 고치지 마세요. 서명이 맞지 않아 오류 202가 나요

주의: 회원 연동 방에서 before.join이 false를 돌려주면 입장이 막히는 것이 아니라 빈 입장 정보로 요청이 가서 오류로 끝나요. 회원 연동 방에서는 before.join으로 입장을 막지 마세요. 입장시키지 않으려면 user_data를 넣지 않거나 태그를 넣지 않아요.

메시지

U.chat('*').on('after.message', function (room, data) {
	console.log(data.user.nick, data.content);
});
키 설명
user 보낸 사람 사용자 객체
content 내용
style { bold, italic, underline, size, color }. color가 없으면 채팅방 기본 글자색
created 보낸 시각 'YYYY-MM-DD HH:MM:SS'(보는 사람의 시간대)
time 보낸 시각(Unix 초)
uid 메시지 고유 번호(16진수 문자열). 없으면 빈 값
past 입장·재접속 때 다시 받은 지난 대화면 true. 새로 올라온 메시지에는 없어요
  • before.message에서 data.content를 고치면 고친 내용이 내 화면에만 보여요.
  • 내가 무시한 사람(부관리자 미만)의 메시지는 before.message까지만 오고 화면 표시와 after.message는 없어요.

귓속말

키 설명
from, to 보낸 사람, 받는 사람 사용자 객체
content 내용
style 지금은 늘 빈 문자열이에요. 메시지의 style 객체와 모양이 달라요
created, time 보낸 시각(문자열, Unix 초)
  • 서버는 귓속말을 보낸 사람과 받는 사람 모두에게 보내요. 그래서 내가 보낸 귓속말도 이 이벤트로 돌아와요. data.from.nick이 내 닉네임이면 내가 보낸 거예요.
  • 메시지와 달리 uid가 없어요.
  • 입장할 때 지난 대화와 함께 나와 관련된 귓속말이 다시 와요.
  • 내가 무시한 사람(부관리자 미만)의 귓속말이거나 내 설정이 귓속말 거부이면 before.whisper까지만 오고 화면 표시와 after.whisper는 없어요.

보내기와 명령

// 보내는 메시지 끝에 서명 붙이기
U.chat('*').on('before.send#sign', function (room, data) {
	data.message += ' ~';
});

// 귓속말 명령 막기
U.chat('*').on('before.command#no-whisper', function (room, data) {
	if (data.type === 'whisper') return false;
});
  • before.send에서 message, bold, italic, underline, color를 고치면 고친 값으로 보내요.
  • before.command의 type은 소문자에 _를 뺀 이름이에요(un_ignore → unignore). data.data(인자 배열)를 고치면 고친 인자로 실행해요.

채널

before.plugin/after.plugin은 두 경우에 오며 data 모양이 달라요.

경우 data
다른 사람이나 서버가 보낸 채널 데이터를 받음 { user, type, data } — user는 보낸 사람, type은 0(모두에게) 또는 1(나에게만), data는 값 배열
채팅창에 !이름 인자 입력(또는 room.action.plugin()) { type: '이름', data: ['인자', ...] } — type이 채널 이름

서버(REST API)가 보낸 데이터와, 입장할 때 다시 받는 채널 저장값은 user.auth가 4이고 닉네임이 비어 있어요. 서버 발신인지는 data.user.auth === 4로만 확인하세요.

받은 데이터에는 채널 이름이 들어 있지 않아요. 채널별로 나눠 받으려면 room.plugin.add(채널).onReceived를 쓰세요. 채널 API와 한도를 보세요.

사용자 변화

U.chat('*').on('after.user.modi', function (room, data) {
	// data.target  바뀌기 전 닉네임
	// data.changed { nick?, auth?, mute? } 중 바뀐 것
	if (data.changed.nick) room.print(data.target + ' → ' + data.changed.nick);
});
  • 입장한 뒤의 변화에만 와요. 내 닉네임·권한·채팅금지가 바뀌어도 오며, 이때 room.my도 바뀌어요. 입장할 때의 권한은 user.join의 data.user나 after.join의 data.my로 봐요.
  • before.user.modi 안에서는 room.my와 room.user.list가 아직 바뀌기 전이에요. room.user.get()은 이미 새 값일 수 있어요.
  • user.join, user.quit이 오지 않고 user.count(3초마다)만 오는 경우가 있어요.
    • 기본 스킨. 사용자 목록이 열려 있든 닫혀 있든 늘 이렇게 와요.
    • 레거시 스킨에서 사용자 목록이 닫혀 있을 때
    • 입장할 때 접속자가 100명 이상인 방
  • 이때는 입장·퇴장이 사용자 목록 화면에만 반영되고, 페이지 스크립트에는 누가 들어오고 나갔는지 알리는 이벤트가 없어요. room.user.list도 갱신되지 않아요. 페이지 스크립트가 믿을 수 있는 것은 접속자 수(user.count)뿐이에요.
  • 입장·퇴장 알림 같은 기능은 레거시 스킨에서 사용자 목록이 열린 작은 방에서만 동작한다고 보고 만드세요. 서버 쪽에서 알아야 하면 서버 REST API의 접속자 수를 써요.
  • user.list 이벤트({ list })는 레거시 스킨에서만 와요. 기본 스킨은 사용자 목록을 나눠 받으므로 이 이벤트가 오지 않아요.

시스템 안내

data.type은 안내 종류, data.data는 값 배열이에요. 값 배열의 모양은 종류마다 달라요.

type 뜻
notice 공지, room.print()
ban 차단
mute, permanent_mute 채팅금지(기간, 영구)
un_mute 채팅금지 해제
to_call, from_call 호출을 보냄, 받음
invite, invite_notice 개인채널 초대를 받음, 보냄
ignore, un_ignore 무시하기, 해제
frozen, unfrozen 채팅방 얼림, 풀림
op, deop 부관리자 지정, 해제
user_info info 명령 결과
ip ip 명령 결과
admin_login, admin_logout 누군가 /login으로 관리자가 됨, 내려놓음
clear_log 대화 청소
muted 채팅금지 중이라 내 메시지가 거절됨
bad_word 단어 필터에 걸려 내 메시지가 거절됨
retry_connect 다시 접속을 시도함(시도 횟수)
U.chat('*').on('after.system', function (room, data) {
	if (data.type === 'from_call') window.focus();
});

호출 받기·초대 받기를 꺼 둔 사용자에게는 from_call, invite의 before.system도 오지 않아요.

제어 신호

data.type은 신호 이름, data.data는 값 배열이에요. 대부분 스킨이 쓰는 내부 신호이므로 이름과 모양이 바뀔 수 있어요. 페이지 스크립트에서 쓸 만한 것은 아래 정도예요.

type 뜻 data
clearLog 대화 청소 []
removeChat 관리자가 메시지를 지움 지운 메시지의 uid 목록. message의 uid와 맞춰 봐요
slowWait 슬로우 모드라 내 메시지가 거절됨 [남은 밀리초, 보내려던 내용]
pluginDataReplaced 무료 방에서 채널 저장값이 바뀜 []. 채널 API와 한도

오류

data.code는 오류 번호이고, 현재 언어의 안내 문구는 room.language.error[code]에 있어요.

U.chat('*').on('after.error', function (room, data) {
	console.warn(data.code, room.language.error[data.code]);
});
코드 뜻
101 프로토콜 오류(잘못된 값, 너무 큰 채널 저장값 등)
201 존재하지 않는 채팅방
301 이미 쓰는 닉네임
202 회원 연동 서명이 맞지 않음
203 회원 연동 방에 접속 정보 없이 접속
205 시간 연동 기준보다 오래된 접속 정보, 또는 처음 쓴 지 5분이 지난 같은 user_data
207 채팅방 인원이 가득 참
208, 701 비밀번호가 틀림, 필요함
402 권한 없음
404 대상이 없음
407 자기 자신에게 쓸 수 없는 명령
410 채팅 권한 없음(기능 조건)
412 명령 인자가 잘못됨
415 차단된 상태
416 이 채팅방에서는 쓸 수 없는 명령
421 이미 그 권한임
422 비밀번호가 틀림
413 채팅금지 중
418 얼린 채팅방
424 내가 귓속말 거부 중이라 보낼 수 없음
425 너무 자주 보냄
428 채널 전송 한도 초과
429 로그인 시도가 너무 많음
430 같은 내용을 반복해 보냄
501, 502 개인채널이 없음, 개인채널 안에서는 개인채널을 만들 수 없음

회원 연동 오류의 원인과 해결은 회원 연동을 보세요.

data 예시

이벤트마다 받는 data의 실제 모양이에요. 값은 예시이고, 서버가 보내지 않은 키는 undefined일 수 있어요. 직접 확인하려면 U.chat('*').on('after.message', function (room, data) { console.log(data); })처럼 콘솔에 찍어 보세요.

// after.join
{ my: { nick: '홍길동', id: 'user1', level: 5, auth: 1, icons: '', nickcon: '',
        connected: '2026-10-17 12:00:00', time: 1792209600, mute: 0, session: 'a1b2c3d4e5f6', profileimg: '' } }

// before.join (회원 연동이 아닌 방)
{ user: { nick: '홍길동' } }

// after.message
{ user: { nick: '홍길동', auth: 1, ... },
  content: '안녕하세요',
  style: { bold: false, italic: false, underline: false, size: '9pt', color: '#000000' },
  created: '2026-10-17 12:00:01', time: 1792209601, uid: '0a1b2c3d4e' }

// after.whisper
{ from: { nick: '홍길동', ... }, to: { nick: '김철수', ... }, style: '', content: '잠깐요',
  created: '2026-10-17 12:00:02', time: 1792209602 }

// before.send
{ message: '안녕하세요', bold: undefined, italic: undefined, underline: undefined, color: undefined }

// before.command  (/w 김철수 잠깐요)
{ type: 'whisper', data: ['김철수', '잠깐요'] }

// after.user.join / after.user.quit
{ user: { nick: '김철수', auth: 0, ... } }
{ user: { nick: '김철수' } }

// after.user.modi
{ target: '김철수', changed: { nick: '철수' } }
{ target: '김철수', changed: { auth: 2 } }
{ target: '김철수', changed: { mute: 1 } }

// after.user.count
{ count: 152 }

// after.update
{ slowSeconds: 5 }

// after.system
{ type: 'mute', data: ['관리자', '김철수', 10, '도배'] } // 관리자, 대상, 분, 사유
{ type: 'from_call', data: ['김철수', '홍길동'] }       // 보낸 사람, 받는 사람

// after.control
{ type: 'removeChat', data: ['0a1b2c3d4e'] }

// after.plugin  (채널 데이터를 받음 / !dice 1 6 입력)
{ user: { nick: '김철수', auth: 1, ... }, type: 0, data: [4] }
{ type: 'dice', data: ['1', '6'] }

// after.error
{ code: 402 }

봐도 잘 이해가 되지 않나요? 문의 게시판에 질문을 남겨 주세요.

상호 UCHAT · 대표 김경욱 · 사업자등록번호 141-05-32832
사업장소재지 경기도 파주시 와석순환로 61 · 통신판매업신고번호 2013-경기파주-4485호
대표번호 010-8677-8633 · 이메일 support@uchat.io

ⓒ 2013–2026 UCHAT. All rights reserved.