Sync your Chess.com games into a Notion database — automatically, with rich metadata and the full move list on every page.
Built as a Notion Worker — no server to run, no API keys to rotate. You deploy it once with the ntn CLI and Notion runs it on a schedule.
A managed "Chess Games" database in your Notion workspace, one row per game, with:
| Column | Type | Description |
|---|---|---|
| Name | Title | white vs black |
| Game ID | Text | Chess.com UUID (primary key) |
| Date | Date | When the game ended, in your timezone |
| Result | Select | Win / Loss / Draw |
| Color | Select | White / Black |
| My Rating | Number | Your rating at time of game |
| Opponent | Link | Opponent's username, links to their Chess.com profile |
| Opponent Rating | Number | |
| Time Control | Select | Bullet / Blitz / Rapid / Daily |
| Time Control (Exact) | Select | e.g. 3 min + 2s, 10 min, 1 day/move |
| Termination | Select | Checkmate / Resignation / Timeout / Stalemate / … |
| Total Moves | Number | |
| Rated | Checkbox | |
| Opening | Text | Opening name (from Chess.com's ECOUrl) |
| ECO Code | Text | e.g. B10 |
| Duration (min) | Number | Wall-clock length of the game |
| Variant | Select | Standard / Chess960 / Bughouse / … |
| Accuracy | Percent | Your accuracy %, when Chess.com provides it |
| Link | URL | Game on Chess.com |
Each page's body contains the full PGN move list, formatted one move-pair per line:
1. e4 .. e5
2. Nf3 .. Nc6
3. Bb5 .. a6
...
That means you can use Notion's filters, sorts, and views to slice your games however you like: blunder hunting by opening, win rate by time control, accuracy trends, etc.
This repo deploys itself: push to master and CI runs ntn workers deploy for you. To set it up on your own fork:
-
Fork this repo on GitHub and clone your fork locally.
-
Get a Notion API token from a Notion integration with workspace access (https://www.notion.so/profile/integrations).
-
First-time setup (local bootstrap). A Notion Worker has to exist before CI can update it, and CI runners can't keep state between runs. So you create the worker once from your laptop, commit its
workers.json, and CI takes over from there:npm i -g ntn # install the Notion CLI ntn login # log in to your Notion workspace rm -f workers.json # drop the upstream author's worker pointer ntn workers deploy --name chess-com-notion-sync # creates your worker; writes a new workers.json git add workers.json git commit -m "Bootstrap my worker" git push
The committed
workers.jsononly holds your worker's UUID — it's not a secret, it's the routing identifier CI uses to find the worker on subsequent deploys. -
Configure the repo in GitHub (Settings → Secrets and variables → Actions):
Kind Name Value Secret NOTION_API_TOKENyour Notion integration token Variable CHESSCOM_USERNAMEyour Chess.com username Variable TIMEZONEe.g. America/Los_Angeles(optional, defaults to LA)Or via the
ghCLI:gh secret set NOTION_API_TOKEN gh variable set CHESSCOM_USERNAME --body "yourusername" gh variable set TIMEZONE --body "America/Los_Angeles"
-
Push to
master(or re-run the latest workflow). CI builds, sets the worker env vars, and deploys.
Notion will then run the sync automatically. The database appears in your workspace under the integration you authorized.
- Incremental: the worker remembers the timestamp of the last game it synced, and only fetches games newer than that.
- Newest-first: Chess.com's archives are paginated by month. The sync walks them newest-first and stops as soon as it hits a month with nothing new — so steady-state runs are cheap.
- Rate-limited: Chess.com asks API consumers for sequential, not parallel, requests. The worker uses Notion's built-in pacer to throttle itself to one request every 500 ms.
- Upsert by game UUID: re-running the sync is safe; rows are keyed on Chess.com's UUID and updated in place.
ntn workers sync status # Check sync status
ntn workers sync trigger chessComNotionSync # Force a sync now
ntn workers sync state reset chessComNotionSync # Re-sync all games from scratch
ntn workers capabilities disable chessComNotionSync # Pause syncing
ntn workers capabilities enable chessComNotionSync # Resume syncingnpm install
npm run check # typecheck
npm run build # emit dist/The worker entrypoint is src/index.ts; the PGN parser is src/pgn.ts.
I built this for chesscards.ai, a chess flashcard app I'm working on, but the sync turned out to be useful on its own — Notion is a surprisingly nice place to keep a chess journal. Automatic ingestion + rich filterable metadata gets you most of the way to a personal Chess.com dashboard with zero infrastructure.
Bug reports, feature ideas, and PRs are welcome. Run npm run check before opening a PR.