Skip to main content
This page documents the message types used for communication between clients and servers, including room initialization, chat, authentication, and global events.

User Representation

USER represents a user with their rank as the first character (users with no rank use a space), followed by their username. Optionally, USER may be appended with @ followed by a status message, or @! to indicate the user is away.

Room Initialization

Init

|init|ROOMTYPE
The first message received when joining a room. ROOMTYPE is one of:
  • chat - A chat room
  • battle - A battle room

Title

|title|TITLE
Sets the room title. The title is not guaranteed to resemble the room ID.
For example, room battle-gen7uu-779767714 could have title Alice vs. Bob.

Users List

|users|USERLIST
Sent when joining chat rooms. USERLIST is a comma-separated list of USERs.

Room Messages

Raw Message

||MESSAGE
or
MESSAGE
Displays MESSAGE directly in the room log.

HTML Message

|html|HTML
Displays sanitized HTML directly in the room log.

Updatable HTML

|uhtml|NAME|HTML
Displays HTML that can be updated later (used for polls, etc.).
|uhtmlchange|NAME|HTML
Updates the HTML of a previous |uhtml| message.

Join

|join|USER
|j|USER
|J|USER
USER joined the room.
  • Lowercase j is for normal display
  • Uppercase J indicates high-frequency events that should not be displayed inline

Leave

|leave|USER
|l|USER
|L|USER
USER left the room.

Name Change

|name|USER|OLDID
|n|USER|OLDID
|N|USER|OLDID
A user changed their name to USER from OLDID.

Chat

|chat|USER|MESSAGE
|c|USER|MESSAGE
USER said MESSAGE.
MESSAGE can contain | characters, so you cannot simply split by | and take the fourth element.

Special Messages

If MESSAGE starts with /, it’s a special command:
  • /me TEXT - Action message
  • /announce TEXT - Announcement
  • /uhtml HTML - HTML in PM (stopgap before client rewrite)
If the server wants to render a message starting with /, it will send it starting with //.

Timestamped Chat

|:|TIMESTAMP
Sets the current server time (UNIX timestamp).
|c:|TIMESTAMP|USER|MESSAGE
Same as |c| but includes a UNIX timestamp for accurate chat logs.

Notify

|notify|TITLE|MESSAGE
Sends a notification. TITLE is usually bold, MESSAGE is optional.
|notify|TITLE|MESSAGE|HIGHLIGHTTOKEN
Sends a notification only if HIGHLIGHTTOKEN would trigger the user’s highlight settings.

Battle Started

|battle|ROOMID|USER1|USER2
|b|ROOMID|USER1|USER2
A battle started between USER1 and USER2 in room ROOMID.

Global Messages

|popup|MESSAGE
Shows a popup containing MESSAGE. || denotes a newline.

Private Message

|pm|SENDER|RECEIVER|MESSAGE
A PM was sent from SENDER to RECEIVER.

User Count

|usercount|USERCOUNT
Indicates the number of users on the server.

Name Taken

|nametaken|USERNAME|MESSAGE
Your attempt to change to USERNAME failed for the reason in MESSAGE.

Authentication

Challenge String

|challstr|CHALLSTR
Received upon connection. Used for authentication.
1

Check for existing session

If you have session cookies, make an HTTP GET request:
https://play.pokemonshowdown.com/api/upkeep?challstr=CHALLSTR
2

Or login with credentials

Make an HTTP POST request with:
https://play.pokemonshowdown.com/api/login
With data:
name=USERNAME&pass=PASSWORD&challstr=CHALLSTR
3

Parse response

The response starts with ] followed by a JSON object. Extract data.assertion.
4

Complete login

Send to the server:
/trn USERNAME,0,ASSERTION
Where ASSERTION is data.assertion from the previous step.

Update User

|updateuser|USER|NAMED|AVATAR|SETTINGS
Your name, avatar, or settings changed successfully.
  • USER - Your rank and username
  • NAMED - 0 if guest, 1 otherwise
  • AVATAR - Your avatar identifier
  • SETTINGS - JSON object with user settings

Format and Search Messages

Formats List

|formats|FORMATSLIST
Lists available battle formats. FORMATSLIST is pipe-separated with these suffixes:
  • ,# - Uses random teams
  • ,, - Only available for searching
  • , - Only available for challenging
Sections are separated by || with column numbers.
|updatesearch|JSON
JSON represents the current state of battle searches. Example:
{
  "searching": ["gen9ou", "gen9randombattle"],
  "games": {
    "battle-gen9ou-12345": "Player1 vs. Player2"
  }
}

Update Challenges

|updatechallenges|JSON
JSON represents current challenge state. Example:
{
  "challengesFrom": {
    "player1": "gen7randombattle"
  },
  "challengeTo": {
    "to": "player2",
    "format": "gen7ou"
  }
}

Query Response

|queryresponse|QUERYTYPE|JSON
Response to /query QUERYTYPE commands. Possible queries:
  • /query roomlist - List of rooms
  • /query userdetails USERNAME - User information

Challenge System

Sending a Challenge

/utm TEAM
/challenge USERNAME, FORMAT
TEAM is in packed format or null for formats like Random Battle.

Accepting a Challenge

/utm TEAM
/accept USERNAME

Rejecting a Challenge

/reject USERNAME

Canceling a Challenge

/cancelchallenge USERNAME

Ladder System

/utm TEAM
/search FORMAT
/cancelsearch

Tournament Messages

Create Tournament

|tournament|create|FORMAT|GENERATOR|PLAYERCAP
  • FORMAT - Battle format name
  • GENERATOR - Elimination or Round Robin
    • Elimination includes prefix: Single, Double, etc.
    • Round Robin includes Double prefix if matchups battle twice
  • PLAYERCAP - Maximum players, or 0 for no cap

Tournament Update

|tournament|update|JSON
JSON object with tournament changes:
{
  "format": "gen9ou",
  "teambuilderFormat": "gen9ou",
  "isStarted": true,
  "isJoined": true,
  "generator": "Single Elimination",
  "playerCap": 16,
  "bracketData": {},
  "challenges": [],
  "challengeBys": [],
  "challenged": null,
  "challenging": null
}

Tournament Events

|tournament|updateEnd
Signals end of update period.
|tournament|error|ERROR
An error occurred.
|tournament|forceend
Tournament was forcibly ended.
|tournament|join|USER
USER joined the tournament.
|tournament|leave|USER
USER left the tournament.
|tournament|replace|OLD|NEW
OLD was replaced with NEW.
|tournament|start|NUMPLAYERS
Tournament started with NUMPLAYERS participants.
|tournament|disqualify|USER
USER was disqualified.

Tournament Battles

|tournament|battlestart|USER1|USER2|ROOMID
Tournament battle started between USER1 and USER2.
|tournament|battleend|USER1|USER2|RESULT|SCORE|RECORDED|ROOMID
Tournament battle ended.
  • RESULT - From USER1’s perspective: win, loss, or draw
  • SCORE - Array [USER1_POKEMON_LEFT, USER2_POKEMON_LEFT]
  • RECORDED - success or fail (if bracket doesn’t support draws)
|tournament|end|JSON
Tournament ended with results:
{
  "results": ["Winner1", "Winner2"],
  "format": "gen9ou",
  "generator": "Single Elimination",
  "bracketData": {}
}

Tournament Settings

|tournament|scouting|SETTING
Scouting is now allow or disallow.
|tournament|autostart|on|TIMEOUT
Auto-start timer set for TIMEOUT seconds.
|tournament|autostart|off
Auto-start timer turned off.
|tournament|autodq|on|TIMEOUT
Auto-disqualify timer set for TIMEOUT seconds.
|tournament|autodq|off
Auto-disqualify timer turned off.
|tournament|autodq|target|TIME
You have TIME seconds to act or be disqualified.

Next Steps

Battle Protocol

Learn about battle-specific message types

Choice Requests

Understand how to make decisions in battles

Build docs developers (and LLMs) love