Answers.Body: <p>There is a better solution for this</p>
  <p>The <code>moveList</code> field of <a href="https://www.chess.com/callback/live/game/2485075845" rel="nofollow noreferrer">https://www.chess.com/callback/live/game/2485075845</a>
  <strong>gv2UmC92lBZRbs!Tpx8!cu5QfH6ZegWOHA0KBKRKuI98vMZSMS1SnvQBsmTZIBKBmBZPAS!?SJPJCJ7Jks47BrJAdc8mfnOGcf78rGAIGrIPad2VrBVufmunmn</strong><br />
  Notice that this string is 2 times the length of the total moves (PlyCount). So each move is encoded into 2 bytes.</p>
  <p>Doing some further research found out that this format that chess.com is something called TCN as seen <a href="https://www.chess.com/clubs/forum/view/official-chess-com-movelist-pgn-help" rel="nofollow noreferrer">here</a>. This can be decoded to UCI format using the scripts in <a href="https://github.com/savi2w/chess-tcn/blob/main/tcn.js" rel="nofollow noreferrer">https://github.com/savi2w/chess-tcn/blob/main/tcn.js</a></p>
  <p>This format will give for each move the data fields <strong>from,to,drop,promotion</strong> which is standard for UCI.</p>
  <p>Now if you have a list of decoded moves, you can convert it to pgn easily using popular chess libraries. I managed to do this in <a href="https://github.com/jhlywa/chess.js" rel="nofollow noreferrer">chess.js</a> and <a href="https://github.com/niklasf/python-chess/tree/master" rel="nofollow noreferrer">python-chess</a> and <a href="https://github.com/niklasf/chessops/" rel="nofollow noreferrer">chessops</a></p>
  <p><a href="https://github.com/cmgchess/chesscom-pgn/blob/master/src/lib/utils.ts#L58" rel="nofollow noreferrer">Here</a> is how I did it with chessops<br />
  <a href="https://github.com/cmgchess/chesscom-pgn/blob/13bba844aefa28b3c6ce09b49a9bec62aad7e49d/src/lib/utils.ts#L39" rel="nofollow noreferrer">Here</a> is how I did it with chess.js</p>
  <p>I also improved on the script used to download tournament games using this way. Now implemented with python-chess<br />
  <a href="https://gist.github.com/cmgchess/1c18df5801184a54355b1bdeb0dceac4" rel="nofollow noreferrer">https://gist.github.com/cmgchess/1c18df5801184a54355b1bdeb0dceac4</a></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2024-07-13T13:20:29.900Z
Answers.LastActivityDate: 2024-07-22T18:22:55.177Z
Answers.LastEditDate: 2024-07-22T18:22:55.177Z
Answers.UserDisplayName: cmgchess
Answers.Body: <p>It is possible to download games from chess.com, otherwise services like <a href="https://www.openingtree.com/" rel="nofollow noreferrer">Opening Tree</a> would not work.</p>
  <p>Chess.com has <a href="https://www.chess.com/news/view/published-data-api" rel="nofollow noreferrer">published it's data API</a>.</p>
  <p>It includes endpoints for <a href="https://www.chess.com/news/view/published-data-api#pubapi-endpoint-games-pgn" rel="nofollow noreferrer">downloading games in PGN format</a>.</p>
  <p>You can access this API programmatically, including Python. It is possible that you have to download multiple games from a player in a batch and then filter the game you're interested in (e.g, using the game URL/game ID, see data format below).</p>
  <p>The data format for games that are returned by this API is</p>
  <pre><code>    {
    &quot;white&quot;: { // details of the white-piece player:
      &quot;username&quot;: &quot;string&quot;, // the username
      &quot;rating&quot;: 1492, // the player's rating after the game finished
      &quot;result&quot;: &quot;string&quot;, // see &quot;Game results codes&quot; section
      &quot;@id&quot;: &quot;string&quot; // URL of this player's profile
    },
    &quot;black&quot;: { // details of the black-piece player:
      &quot;username&quot;: &quot;string&quot;, // the username
      &quot;rating&quot;: 1942, // the player's rating after the game finished
      &quot;result&quot;: &quot;string&quot;, // see &quot;Game results codes&quot; section
      &quot;@id&quot;: &quot;string&quot; // URL of this player's profile
    },
    &quot;accuracies&quot;: { // player's accuracies, if they were previously calculated
      &quot;white&quot;: float,
      &quot;black&quot;: float
    },
    &quot;url&quot;: &quot;string&quot;, // URL of this game
    &quot;fen&quot;: &quot;string&quot;, // final FEN
    &quot;pgn&quot;: &quot;string&quot;, // final PGN
    &quot;start_time&quot;: 1254438881, // timestamp of the game start (Daily Chess only)
    &quot;end_time&quot;: 1254670734, // timestamp of the game end
    &quot;time_control&quot;: &quot;string&quot;, // PGN-compliant time control
    &quot;rules&quot;: &quot;string&quot;, // game variant information (e.g., &quot;chess960&quot;)
    &quot;eco&quot;: &quot;string&quot;, //URL pointing to ECO opening (if available),
    &quot;tournament&quot;: &quot;string&quot;, //URL pointing to tournament (if available),  
    &quot;match&quot;: &quot;string&quot;, //URL pointing to team match (if available)  
  }
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-23T03:59:57.620Z
Answers.Text: does most of these apis require a userId as well. Since i'm only interested in a single game it would take a lot of time to say filter it out from a user having 1000s of games
Answers.UserDisplayName: cmgchess
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-23T13:55:25.780Z
Answers.Text: Why do you think would it take a lot of time to filter the games? Even processing 1000 games should not take more than a fraction of a second. The server response will not be slower for 1000 games than for 1 game, except the actual download time (that's of course longer for more data). Plus, you can get monthly archives, so it will never be 1000s of games, unless the player really played 1000s of games in a single month.
Answers.UserDisplayName: Hauptideal
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-23T15:56:34.337Z
Answers.Text: actually my plan is to collect all the game ids of a certain titled tuesday and create a pgn of all the games. will see how it goes
Answers.UserDisplayName: cmgchess
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-12-03T10:12:33.647Z
Answers.Text: Thanks it worked and i managed to achieve what i wanted. [Link](https://gist.github.com/cmgchess/1c18df5801184a54355b1bdeb0dceac4) for anyone interested
Answers.UserDisplayName: cmgchess
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-22T23:33:31.233Z
Answers.LastActivityDate: 2023-11-22T23:33:31.233Z
Answers.UserDisplayName: Hauptideal
Body: <p>Every chess.com game has a <strong>game ID</strong>. For example <strong><a href="https://www.chess.com/game/live/2485075845" rel="nofollow noreferrer">https://www.chess.com/game/live/2485075845</a></strong> <strong><code>2485075845</code></strong> is the game ID. When you go to this URL it is possible to download the PGN by clicking the share button.<br />
  Is there a way to do this programmatically (say using Python) so I can pass in the game ID and download it directly using a Python script<br />
  I noticed that <strong><a href="https://www.chess.com/callback/live/game/2485075845" rel="nofollow noreferrer">https://www.chess.com/callback/live/game/2485075845</a></strong> gives all the data that is related to the game but the <code>moveList</code> is showing in some kind of hashed format which I have no idea how to decode.</p>
  <p>Appreciate if anyone can help with this.</p>
  
Tags: <software><programming><pgn><python><chess.com>
Title: how to download pgn of a chess.com game by game ID programmatically
ThreadText: # how to download pgn of a chess.com game by game ID programmatically
  
  (Asked by: username_0 on 2023-11-22)
  
  Every chess.com game has a **game ID**. For example **<https://www.chess.com/game/live/2485075845>** **`2485075845`** is the game ID. When you go to this URL it is possible to download the PGN by clicking the share button.  
  Is there a way to do this programmatically (say using Python) so I can pass in the game ID and download it directly using a Python script  
  I noticed that **<https://www.chess.com/callback/live/game/2485075845>** gives all the data that is related to the game but the `moveList` is showing in some kind of hashed format which I have no idea how to decode.
  
  Appreciate if anyone can help with this.
  
  **Tags:** software, programming, pgn, python, chess.com
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_0 on 2024-07-13. Score: 1 | Accepted answer
  
  There is a better solution for this
  
  The `moveList` field of <https://www.chess.com/callback/live/game/2485075845>
  **gv2UmC92lBZRbs!Tpx8!cu5QfH6ZegWOHA0KBKRKuI98vMZSMS1SnvQBsmTZIBKBmBZPAS!?SJPJCJ7Jks47BrJAdc8mfnOGcf78rGAIGrIPad2VrBVufmunmn**  
  Notice that this string is 2 times the length of the total moves (PlyCount). So each move is encoded into 2 bytes.
  
  Doing some further research found out that this format that chess.com is something called TCN as seen [here](https://www.chess.com/clubs/forum/view/official-chess-com-movelist-pgn-help). This can be decoded to UCI format using the scripts in <https://github.com/savi2w/chess-tcn/blob/main/tcn.js>
  
  This format will give for each move the data fields **from,to,drop,promotion** which is standard for UCI.
  
  Now if you have a list of decoded moves, you can convert it to pgn easily using popular chess libraries. I managed to do this in [chess.js](https://github.com/jhlywa/chess.js) and [python-chess](https://github.com/niklasf/python-chess/tree/master) and [chessops](https://github.com/niklasf/chessops/)
  
  [Here](https://github.com/username_0/chesscom-pgn/blob/master/src/lib/utils.ts#L58) is how I did it with chessops  
  [Here](https://github.com/username_0/chesscom-pgn/blob/13bba844aefa28b3c6ce09b49a9bec62aad7e49d/src/lib/utils.ts#L39) is how I did it with chess.js
  
  I also improved on the script used to download tournament games using this way. Now implemented with python-chess  
  <https://gist.github.com/username_0/1c18df5801184a54355b1bdeb0dceac4>
  
  
  ---
  
  ### Answer by username_1 on 2023-11-22. Score: 4
  
  It is possible to download games from chess.com, otherwise services like Opening Tree would not work.
  Chess.com has published it's data API.
  It includes endpoints for downloading games in PGN format.
  You can access this API programmatically, including Python. It is possible that you have to download multiple games from a player in a batch and then filter the game you're interested in (e.g, using the game URL/game ID, see data format below).
  The data format for games that are returned by this API is
      {
    "white": { // details of the white-piece player:
      "username": "string", // the username
      "rating": 1492, // the player's rating after the game finished
      "result": "string", // see "Game results codes" section
      "@id": "string" // URL of this player's profile
    },
    "black": { // details of the black-piece player:
      "username": "string", // the username
      "rating": 1942, // the player's rating after the game finished
      "result": "string", // see "Game results codes" section
      "@id": "string" // URL of this player's profile
    },
    "accuracies": { // player's accuracies, if they were previously calculated
      "white": float,
      "black": float
    },
    "url": "string", // URL of this game
    "fen": "string", // final FEN
    "pgn": "string", // final PGN
    "start_time": 1254438881, // timestamp of the game start (Daily Chess only)
    "end_time": 1254670734, // timestamp of the game end
    "time_control": "string", // PGN-compliant time control
    "rules": "string", // game variant information (e.g., "chess960")
    "eco": "string", //URL pointing to ECO opening (if available),
    "tournament": "string", //URL pointing to tournament (if available),  
    "match": "string", //URL pointing to team match (if available)  
  }
  
  > **Comments:**
  > **username_0**: does most of these apis require a userId as well. Since i'm only interested in a single game it would take a lot of time to say filter it out from a user having 1000s of games  
  > **username_1**: Why do you think would it take a lot of time to filter the games? Even processing 1000 games should not take more than a fraction of a second. The server response will not be slower for 1000 games than for 1 game, except the actual download time (that's of course longer for more data). Plus, you can get monthly archives, so it will never be 1000s of games, unless the player really played 1000s of games in a single month.  
  > **username_0**: actually my plan is to collect all the game ids of a certain titled tuesday and create a pgn of all the games. will see how it goes  
  > **username_0**: Thanks it worked and i managed to achieve what i wanted. [Link](https://gist.github.com/username_0/1c18df5801184a54355b1bdeb0dceac4) for anyone interested  
  
  ---
  
  