Agora RTM으로 실시간 채팅 구현하기
Agora RTM의 login, channel subscribe, publish, unsubscribe, logout 수명주기로 채팅을 구현합니다. RTC channel과 RTM channel의 식별자를 함께 사용할 수 있지만 연결과 token 권한은 별도라는 점을 구분하고, message validation·rate limit·한글 IME composition 처리도 다룹니다.
Agora RTM(Real-Time Messaging)은 실시간 텍스트 메시징과 시그널링을 위한 경량 SDK입니다. 화상 통화(RTC)와 함께 사용하면 채널 내 채팅, 손들기, 참가자 상태 등을 안정적으로 구현할 수 있습니다. 이 글에서는 RTM으로 실시간 채팅 시스템을 구축하는 방법과 모범 사례를 정리합니다.
RTM이란?
RTM은 Agora의 실시간 메시징 서비스로, 음성·영상이 아닌 데이터를 빠르게 주고받을 때 사용합니다.
- 채널 메시지: 특정 채널을 구독한 모든 사용자에게 메시지 브로드캐스트
- 시그널링: 화면 공유 시작/중지, 손들기, 호스트·시청자 역할 등 앱 단위 이벤트를 JSON으로 전달
- 저지연: 전용 인프라로 짧은 지연 시간과 높은 도달률을 목표로 설계됨
RTC(화상·음성)와 RTM(텍스트·시그널링)은 별도 SDK와 권한 범위를 사용하며, 같은 Agora App ID 아래에서 채널명과 사용자 식별자를 맞춰 함께 사용할 수 있습니다. 이 글의 예시는 운영과 권한 분리를 위해 토큰 API도 나누지만, AccessToken2에는 RTC와 RTM 권한을 함께 담을 수도 있습니다.
같은 방(채널) 하나에 두 개의 독립 파이프라인이 나란히 붙는 구조입니다.
준비 사항
- Agora 콘솔: 프로젝트의 App ID, App Certificate
- RTM 토큰 서버: App Certificate는 서버에만 두고, 클라이언트에는 userId로 요청한 RTM 토큰만 내려주는 API를 구현합니다.
- 패키지:
agora-rtm-sdk(Web)
전체 흐름 요약
- RTM 클라이언트 생성 →
new RTM(APP_ID, userId) - 토큰 발급 → 백엔드에서 userId 기준 RTM 토큰 발급
- 로그인 →
rtm.login({ token }) - 채널 구독 →
rtm.subscribe(channelName)→ 해당 채널 메시지 수신 가능 - 메시지 발송 →
rtm.publish(channelName, message) - 메시지 수신 →
rtm.addEventListener("message", handler)에서event.publisher,event.message처리 - 퇴장 →
rtm.logout()
아래 코드는 프로젝트의 app/agora-demo/rtc/page.tsx에서 사용한 RTM 채팅 흐름을 참고한 예시입니다.
1. RTM 클라이언트 생성 및 로그인
RTM은 사용자 단위로 동작합니다. userId는 문자열로, RTC의 uid와 맞춰 두면 같은 사용자를 하나의 주체로 다루기 쉽습니다.
- RTC 채널 토큰(
/api/token)과 RTM 사용자 토큰(/api/rtm-token)은 서로 다른 API에서 발급하는 구성을 권장합니다.
2. 채널 구독 및 메시지 수신
채팅을 하려면 채널을 구독해야 합니다. 구독한 채널로 들어오는 모든 메시지를 message 이벤트로 받을 수 있습니다.
- 채널 메시지는 해당 채널을 구독한 모든 사용자에게 전달됩니다.
- 메시지가 문자열 또는 Uint8Array로 올 수 있으므로, 바이너리일 때는
TextDecoder로 디코딩하는 것이 안전합니다.
3. 메시지 발송
채널에 텍스트를 보낼 때는 rtm.publish(channelName, message)를 사용합니다. 메시지는 문자열로 보내며, JSON 문자열을 사용하면 타입별 시그널링을 나눌 수 있습니다.
- 발송 성공 후 자신의 메시지는 곧바로 로컬 UI에 추가하고,
message이벤트에서는publisher === 자신인 경우는 스킵하면 중복 표시를 막을 수 있습니다.
4. 한글 IME 중복 전송 방지
한글처럼 조합형 입력(IME)을 쓰는 경우, 조합 확정에 사용한 Enter를 메시지 전송으로 처리하면 의도하지 않은 전송이 생길 수 있습니다. 시간·문자열 길이 휴리스틱은 정상적인 짧은 메시지를 버릴 수 있으므로, 표준 KeyboardEvent.isComposing과 composition 이벤트를 사용합니다.
isComposing이true인 keydown은 조합 확정 입력이므로 전송하지 않습니다. 전송 요청 자체의 중복 방지는 별도의 요청 ID나 버튼 비활성화로 처리합니다.
5. 시그널링 확장 (타입별 메시지)
채팅과 시그널링을 같은 채널에서 구분하려면 JSON으로 type 필드를 두고 처리하는 방식을 많이 씁니다.
| type | 용도 |
|---|---|
| (없음 또는 일반 텍스트) | 채팅 메시지 |
screen | 화면 공유 시작/중지 알림 (start, uid) |
presence | 참가자 수·역할 (라이브 스트리밍에서 호스트/시청자 수 등) |
signaling | 손들기, 질문 요청 등 (예: action: "raise_hand", fromUid) |
예시:
6. 퇴장 시 정리
채널을 나갈 때는 RTM 로그아웃을 호출해 연결과 리소스를 정리합니다. RTC와 함께 쓰는 경우에는 RTC leave 및 트랙 close 후 rtm.logout()을 호출하면 됩니다.
RTC와 함께 쓸 때 정리
| 구분 | RTC | RTM |
|---|---|---|
| 역할 | 음성·영상 스트림 | 텍스트·시그널링 |
| 토큰 | 채널·uid 기준 RTC 토큰 | userId 기준 RTM 토큰 |
| 입장 | client.join(appId, channelName, token, uid) | rtm.login({ token }) + rtm.subscribe(channelName) |
| 퇴장 | client.leave(), 트랙 close() | rtm.logout() |
- 같은 채널명을 사용하면, 화상 통화 방 하나에 RTC(영상/음성)와 RTM(채팅·시그널링)을 동시에 붙일 수 있습니다.
- 실제 구현 예는 Agora Demo > RTC - Call (
/agora-demo/rtc)에서 채팅 패널과 화면 공유 알림을 확인할 수 있고, Live Streaming 데모에서는 손들기·참가자 수(presence)까지 RTM으로 처리하고 있습니다.
참고
- 이 예시는 RTM 토큰을 별도 백엔드 API에서 발급합니다. 하나의 AccessToken2를 쓸 때는 RTC와 RTM 권한을 모두 포함해야 합니다.
- 메시지 크기·빈도 제한은 Agora Signaling 제한 사항을 참고하세요.
- 기본 API 흐름은 Agora Signaling Web quickstart를 참고하세요.
RTC 화상 통화 구현은 Agora RTC를 활용한 실시간 화상 통화 구현하기 글을 참고하세요.
관련 글
- #2 Agora RTC 실시간 화상통화 구현 — 같은 채널명에 RTM 채팅을 얹는 기준이 되는 RTC 입장/트랙 흐름
- #4 Agora RTC 라이브스트리밍 구현 — 호스트/시청자 역할과 presence·손들기 시그널링을 RTM으로 처리하는 사례
- #5 Conversational AI 통합 가이드 — AI 에이전트와의 상호작용에서 RTM 시그널링/전사 데이터 채널을 함께 쓰는 구성
- #10 실시간 Agent STT + 번역 구현 — 별도 Real-Time STT 제품이 RTC DataStream으로 Protobuf 자막을 전달하는 구조
참고 자료
- Signaling SDK Web quickstart —
login/subscribe/publish/이벤트 리스너 기본 흐름 - Signaling limitations — 메시지 크기·전송 빈도 등 RTM 제한 사항
- Agora AccessToken2 Node.js builder —
buildTokenWithRtm2로 RTC·RTM 서비스를 한 토큰에 넣는 공식 구현 - Signaling SDK API Reference (Web) — RTM 2.x JS SDK 클래스/메서드 레퍼런스
- W3C Encoding: TextDecoder — 바이너리(Uint8Array) 메시지를 문자열로 디코딩하는 표준 인터페이스
- W3C UI Events — KeyboardEvent.isComposing — IME 조합 중 keydown 판별 기준
실제 데모
/agora-demo/rtc