Skip to main content

Documentation Index

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

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

The Pokémon Showdown client is entirely driven by a global Config object that is injected into the page as a <script> tag before any client JavaScript runs. When you visit play.pokemonshowdown.com, this object is served dynamically by the production PS server at /config/config.js. When you run your own instance or use the test client, you control it yourself — making it the single most important file to understand before customizing the client.

The PSConfig Interface

The Config global is typed as PSConfig in TypeScript (declared in play.pokemonshowdown.com/src/client-main.ts):
export declare const Config: PSConfig;
The full interface looks like this:
export interface ServerInfo {
  id: ID;           // lowercase alphanumeric server identifier
  protocol: string; // 'http' or 'https'
  host: string;     // hostname, e.g. 'sim3.psim.us'
  port: number;     // primary WebSocket port
  httpport?: number; // optional HTTPS port (presence implies HTTPS)
  altport?: number;  // optional fallback port
  prefix: string;   // socket path prefix, e.g. '/showdown'
  afd?: boolean;    // April Fools' Day mode flag
  registered?: boolean; // whether this server uses registered login
}

export interface PSConfig {
  server: ServerInfo;         // currently connected server
  defaultserver: ServerInfo;  // server used when on the canonical domain
  routes: {
    root: string;     // root domain, e.g. 'pokemonshowdown.com'
    client: string;   // client domain, e.g. 'play.pokemonshowdown.com'
    dex: string;      // dex domain, e.g. 'dex.pokemonshowdown.com'
    replays: string;  // replays domain, e.g. 'replay.pokemonshowdown.com'
    users: string;    // user pages, e.g. 'pokemonshowdown.com/users'
    teams: string;    // teams domain, e.g. 'teams.pokemonshowdown.com'
  };
  customcolors: Record<string, string>; // username → color hex override
  whitelist?: string[];     // optional: allowed server IDs for multi-server mode
  testclient?: boolean;     // true when running in the test client
}

Field Reference

server

The active server the client connects to. The test client overrides this from the ?~~host:port query string. Contains the WebSocket host, port, prefix path, and flags like afd and registered.

defaultserver

The server to use when the page is loaded from the canonical Config.routes.client domain. The production config points this to sim3.psim.us:443. Your own builds should point it at your server host.

routes

Six URL prefixes (no trailing slash) that the client uses to construct links to the Pokédex, replays, user pages, and the teams builder. The production values come from config/routes.json.

customcolors

A plain object mapping lowercase usernames to hex color strings. These override the algorithmic color generation for specific users. Example: { "zarel": "aeo" }.

whitelist

Optional. When present, restricts which server IDs the client will allow connections to. The production whitelist is a large list of approved domains maintained server-side.

testclient

A boolean flag set to true inside testclient-old.html immediately after loading config.js. It unlocks test-only UI elements and relaxes certain production-only guards.

How Config Is Loaded

The client never fetches Config — it relies on the server to inject it as a plain <script> tag before any client bundle runs. In the test client HTML (testclient-old.html), you can see this pattern directly:
<!-- Loads the production Config from the live PS server -->
<script src="https://play.pokemonshowdown.com/config/config.js"></script>
<script>
  Config.testclient = true;

  // Override server from the query string: ?~~host:port
  (function() {
    if (location.search !== '') {
      var m = /\?~~(([^:\/]*)(:[0-9]*)?)/.exec(location.search);
      if (m) {
        Config.server = {
          id: m[1],
          host: m[2],
          port: (m[3] && parseInt(m[3].substr(1))) || 8000
        };
      }
    }
  })();
</script>
The test client deliberately loads the production config.js and then mutates Config inline. This means your local test instance inherits the production route URLs, whitelist, and custom colors — and only overrides server and testclient.

Sample Config Structure

For your own Pokémon Showdown server deployment, your config/config.js should follow this pattern (based on config/config-example.js):
/** @type {import('../play.pokemonshowdown.com/src/client-main').PSConfig} */
var Config = Config || {};

Config.defaultserver = {
  id: 'myserver',
  host: 'myserver.example.com',
  port: 443,
  httpport: 8000,
  altport: 80,
  registered: true
};

Config.routes = {
  root:    'pokemonshowdown.com',
  client:  'play.pokemonshowdown.com',
  dex:     'dex.pokemonshowdown.com',
  replays: 'replay.pokemonshowdown.com',
  users:   'pokemonshowdown.com/users',
  teams:   'teams.pokemonshowdown.com',
};

Config.customcolors = {
  'yourusername': '#4a90d9'
};

Config.whitelist = [
  'wikipedia.org'
  // Add your own allowed server IDs here
];
The full production whitelist is maintained outside this repository so changes don’t clutter the commit log. The example only contains a placeholder entry. If you are running a private instance, you can omit whitelist entirely or set it to an empty array.

Production vs. Custom Instances

On play.pokemonshowdown.com, the server generates config.js dynamically and includes the full whitelist, registered server information, and custom color assignments for all known users. You do not interact with this file directly — it is controlled by the Pokémon Showdown team.
When running your own instance of the client, you must provide your own config.js. The minimum required fields are defaultserver (your server’s host and port) and routes (the URL domains for cross-links). All other fields are optional.Copy config/config-example.js as your starting point and adjust the defaultserver and routes fields to match your deployment.
The test client (testclient-old.html) is a special case: it loads the production config.js from play.pokemonshowdown.com and then immediately overrides Config.server from the query string and sets Config.testclient = true. This means you get production routes and custom colors for free, while pointing the socket connection at a local or custom server.

TypeScript Declaration

Because Config is injected via a <script> tag and not an ES module import, TypeScript only knows about it through an ambient declaration in client-main.ts:
export declare const Config: PSConfig;
This means the TypeScript compiler trusts that Config will be present at runtime but does not bundle or validate the actual JS file. If your config.js is missing or malformed, the client will fail silently or throw runtime errors — there is no compile-time check.
Always validate your config.js by loading it in a browser console before deploying. The most common mistake is omitting the defaultserver.host field or using a mismatched port number.

Build docs developers (and LLMs) love