How to download all your games using chess.com API

How to download all your games using chess.com API

Avatar of MrChatty
| 10

There is no built-in feature to download all your games on chess.com (at least by the moment I published this). One way is to use some third-party online services. The other approach is to use chess.com API and do some programming yourself which is the subject of this small article. The powerful codes below let you download all your games in a single PGN file. Note that some games (e.g. Bug House) do not have PGN records and hence will not get into the final file.

chess.com API

The games can be accessed via chess.com API in several steps:

  1. Requesting the monthly archives in JSON format
  2. Requesting the list of games from each monthly archive in JSON format
  3. Extracting the text PGN record from each game

Python

Requires the standard Python environment installed in your system and basic skill to edit and to run Python scripts, to install third-party libraries (the requests library is needed). The entire script is below:


PLAYER = "MrChatty"

import requests

def get_json(url):
    response = requests.get(url, headers={"User-Agent": "Tool"})

    if response.status_code == 200:
        return response.json()

    print(f"Could not download [{url}], code {response.status_code}")
    return None

print("Downloading archives...")

url = f"https://api.chess.com/pub/player/{PLAYER}/games/archives"
json = get_json(url)

if json:
    print("Archives downloaded successfully")
    print("Downloading games...")

    urls = json["archives"]
    games = []

    for url in urls:
        json = get_json(url)

        if json:
            games.extend(json["games"])                        

    pgns = [game["pgn"] for game in games if "pgn" in game]
    filename = f"{PLAYER}.pgn"
    
    with open(filename, "w", encoding="utf-8") as f:
        f.write("\n\n".join(pgns))

    print(f"{len(pgns)} games downloaded to [{filename}]")


Create an empty Python file, copy the code into it, change the value of the PLAYER parameter in the first line to your username, save and run the script. Some text messages will appear while the script is running: 

The result is saved into {username}.pgn file near the Python file.

HTML + CSS + JavaScript

Requires a modern web browser such as Chrome or Firefox. The entire code of web page with embedded scripts is below:


<!DOCTYPE html>
<html>
<head>
<title>Tool to Download Games from chess.com</title>
<style>
body {text-align: center;}
</style>
<script>
    function disableUi(flag) {
        document.getElementById("username").disabled = flag;
        document.getElementById("download").disabled = flag;
    }

    function getUserName() {
        return document.getElementById("username").value;
    }

    function clearStatus() {
        document.getElementById("status").innerHTML = "";
    }

    function updateStatus(text) {
        document.getElementById("status").innerHTML += `${text}<br>`;
    }

    function save(text, fileName) {
        const blob = new Blob([text], {type: "text/plain"});
        const href = URL.createObjectURL(blob);
        const link = document.createElement("a");
        
        link.download = fileName;
        link.href = href;
        
        document.body.appendChild(link);
        link.click();
        
        document.body.removeChild(link);
        URL.revokeObjectURL(link);
    }

    async function getJson(url) {
        const response = await fetch(url);
        
        if (response.ok)
            return response.json();
        
        updateStatus(`Could not download [${response.url}], code ${response.status}`);
        return null;
    }

    async function download() {
        disableUi(true);
        clearStatus();
        
        try {
            updateStatus("Downloading archives...");
            
            const userName = getUserName();
            const url = `https://api.chess.com/pub/player/${userName}/games/archives`;
            const json = await getJson(url);
            
            if (json) {
                updateStatus("Archives downloaded successfully");
                updateStatus("Downloading games...");
                
                const urls = json.archives;
                const games = [];
                
                for (const url of urls) {
                    const json = await getJson(url);
                    
                    if (json)
                        games.push(...json.games);
                }
                
                const pgns = games.filter(game => "pgn" in game)
                    .map(game => game.pgn);
                    
                updateStatus(`${pgns.length} games downloaded`);
                save(pgns.join("\n\n"), `${userName}.pgn`);
            }
        }
        finally {        
            disableUi(false);
        }
    }
</script>
</head>
<body>
<label>Player</label>
<input type="text" id="username" value="MrChatty">
<button id="download" onclick="download();">Download games from chess.com</button>
<br>
<label id="status"></label>
</body>
</html>


Create an empty text file, copy the code into it, save the file as HTML web page and open in your web browser, the glamorous interface will appear:

Enter your username in the text field and press the button. Some text messages will appear while the script is running:

The result is saved into {username}.pgn file.

Hint: to change the default username edit the value attribute in the line 91.

PGN size

If we consider an average game with 30 moves (60 plies) the size of its PGN file would be approximately 2.2...2.5 kB. Do some math before running the scripts to ensure there is enough space for the final PGN file.