Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/smogon/pokemon-showdown/llms.txt

Use this file to discover all available pages before exploring further.

This guide covers how to interact with the Pokemon Showdown battle simulator using the Node.js API.

Basic Setup

Creating a Battle

The simulator uses BattleStream as its primary interface:
const Sim = require('pokemon-showdown');
const stream = new Sim.BattleStream();

// Read output from the battle
(async () => {
    for await (const output of stream) {
        console.log(output);
    }
})();

// Start the battle
stream.write(`>start {"formatid":"gen9ou"}`);
stream.write(`>player p1 {"name":"Alice","team":"<packed team>"}`);
stream.write(`>player p2 {"name":"Bob","team":"<packed team>"}`);
Teams must be provided in packed format for non-random formats.

Writing to the Simulator

All messages written to the simulator must start with >. Lines without > are treated as comments.

Start Command

Initialize a battle with format options:
>start OPTIONS
OPTIONS is a JSON object with these properties:
formatid
string
required
The format ID (e.g., "gen9ou", "gen9randombattle")
seed
number[]
Array of four numbers for PRNG seed (defaults to random)
p1
PlayerOptions
Player 1 options (alternative to separate >player p1 command)
p2
PlayerOptions
Player 2 options (alternative to separate >player p2 command)
p3
PlayerOptions
Player 3 options for 4-player battles
p4
PlayerOptions
Player 4 options for 4-player battles

Example

stream.write(`>start {"formatid":"gen9ou","seed":[1,2,3,4]}`);

Player Command

Set player information:
>player PLAYERID PLAYEROPTIONS
PLAYERID is p1, p2, p3, or p4. PLAYEROPTIONS is a JSON object:
name
string
Player name (defaults to “Player 1” or “Player 2”)
avatar
string
Player avatar identifier (defaults to empty string)
team
string | PokemonSet[]
Team in packed format or JSON format
Teams are not validated automatically. Use TeamValidator first to ensure legality.

Example

stream.write(`>player p1 {"name":"Alice","team":"<packed team>"}`);
stream.write(`>player p2 {"name":"Bob","team":"<packed team>"}`);

Choice Commands

Submit player decisions:
>p1 CHOICE
>p2 CHOICE
>p3 CHOICE
>p4 CHOICE
CHOICE can be:
  • move MOVENUM - Use a move (e.g., move 1)
  • switch POKEMONNUM - Switch Pokemon (e.g., switch 3)
  • team TEAMORDER - Select team order in Team Preview (e.g., team 123456)
For complete choice documentation, see SIM-PROTOCOL.md.

Example Turn

// Team Preview
stream.write(`>p1 team 123456`);
stream.write(`>p2 team 123456`);

// Turn 1
stream.write(`>p1 move 1`);
stream.write(`>p2 switch 3`);

// Turn 2
stream.write(`>p1 move 3`);
stream.write(`>p2 move 2`);

Reading from the Simulator

The simulator outputs messages delimited by \n\n in text streams, or as separate strings in object streams.

Message Types

Messages for all players and spectators:
update
MESSAGES
Contains battle state updates following the SIM-PROTOCOL format.

Split Messages

Private information is sent using |split|PLAYERID:
|split|p1
SECRET
PUBLIC
  • SECRET - Messages with exact details (e.g., exact HP) for the player or omniscient observer
  • PUBLIC - Messages with public details for opponents/spectators (may be empty)

Complete Example

Here’s a full example with team generation and battle simulation:
const Sim = require('pokemon-showdown');
const { Teams } = Sim;

// Generate random teams
const team1 = Teams.pack(Teams.generate('gen9randombattle'));
const team2 = Teams.pack(Teams.generate('gen9randombattle'));

// Create battle stream
const stream = new Sim.BattleStream();

// Listen to battle output
(async () => {
    for await (const output of stream) {
        console.log(output);
    }
})();

// Start battle
stream.write(`>start {"formatid":"gen9randombattle"}`);
stream.write(`>player p1 {"name":"Alice","team":${JSON.stringify(team1)}}`);
stream.write(`>player p2 {"name":"Bob","team":${JSON.stringify(team2)}}`);

// Make choices (in a real scenario, parse choice requests first)
stream.write(`>p1 move 1`);
stream.write(`>p2 move 1`);

Advanced Options

BattleStream Options

You can pass options when creating a BattleStream:
const stream = new Sim.BattleStream({
    debug: true,        // Enable debug mode
    noCatch: false,     // Disable error catching (errors will throw)
    keepAlive: false,   // Keep stream alive after battle ends
    replay: false       // Enable replay mode ('spectator' for spectator view)
});

Seeded Battles

For reproducible battles, provide a seed:
stream.write(`>start {"formatid":"gen9ou","seed":[1,2,3,4]}`);
The same seed with the same inputs will produce identical battles.

Force Commands

You can force battle outcomes:
>forcewin PLAYERID    // Force a player to win
>forcetie             // Force a tie
>forcelose PLAYERID   // Force a player to lose
Force commands should only be used for testing or administrative purposes.

Error Handling

Errors in player choices are sent as |error| messages in sideupdate:
sideupdate
p1
|error|[Invalid choice] ...
To handle errors in your code:
for await (const output of stream) {
    const [type, data] = output.split('\n', 2);
    
    if (type === 'sideupdate') {
        const [playerid, ...messages] = data.split('\n');
        if (messages.some(msg => msg.startsWith('|error|'))) {
            console.error('Invalid choice detected');
        }
    }
}

Next Steps

BattleStream API

Deep dive into BattleStream and player streams

Team Formats

Learn about team format conversions