Your first analysis
Run your first analysis on a small PGN file and see exactly what you get back.
This page walks you through a complete analysis, start to finish, on a tiny example file — so you can follow along and compare your output with ours.
The example file
Save these three games as games.pgn. They are deliberately short (a quick win, a quicker loss, and a draw), and we'll reuse this file throughout the guides:
[Event "Casual Blitz game"]
[Site "https://lichess.org/a1b2c3d4"]
[Date "2024.05.12"]
[White "alice"]
[Black "blunderbuss"]
[Result "1-0"]
[WhiteElo "2114"]
[BlackElo "1892"]
[ECO "C23"]
1. e4 e5 2. Bc4 Nc6 3. Qh5 Nf6 4. Qxf7# 1-0
[Event "Rated Bullet game"]
[Site "https://lichess.org/e5f6g7h8"]
[Date "2024.05.13"]
[White "blunderbuss"]
[Black "cleopatra"]
[Result "0-1"]
[WhiteElo "1650"]
[BlackElo "1701"]
[ECO "A02"]
1. f3 e5 2. g4 Qh4# 0-1
[Event "Rated Rapid game"]
[Site "https://lichess.org/i9j0k1l2"]
[Date "2024.05.14"]
[White "alice"]
[Black "cleopatra"]
[Result "1/2-1/2"]
[WhiteElo "1987"]
[BlackElo "2005"]
[ECO "B20"]
1. e4 c5 2. Nf3 d6 3. Bb5+ Bd7 4. Bxd7+ Qxd7 1/2-1/2Running the analysis
We'll ask the built-in tileTracker to watch every square of the board — who moved where, who got captured where, and how long each piece stayed put:
import { analyzePGN } from 'chessalyzer';
import { tileTracker } from 'chessalyzer/trackers';
const tiles = tileTracker();
const result = await analyzePGN('games.pgn', { trackers: [tiles] });
console.log(result);Two things to notice: you create a tracker instance (tileTracker()) and hand it over, and after the call you read your results from that same instance. For a deeper look check out Trackers.
What you get back
analyzePGN returns a small summary of the run itself — how many games and half-moves were processed, and how long it took:
{
// Total processed games and half-moves
gameCount: 3,
moveCount: 19,
// Performance meta
perf: {
durationMs: 33.99,
movesPerSecond: 559,
},
// Processed games and half-moves per run; for a single run this matches the overall totals
runs: [
{
gameCount: 3,
moveCount: 19,
},
],
}Your performance numbers will differ
The perf entries (durationMs and movesPerSecond) depend on your machine, and 3 games
finish in the blink of an eye — throughput gets interesting on files with thousands or millions
of games. Chessalyzer is carefully tuned for performance by utilizing
Multithreading and other techniques.
Multi-run analyses
The runs array has one entry per analysis pass and since we only ran one analysis cohort
there's exactly one entry here. See Comparing groups for how to run
multiple analyses at once.
The actual collected statistics live on your tracker. tiles.state counts 19 half-moves, and each square has its own little report — here's the one for e4, the square white's king pawn moved to in two of our three games:
console.log(tiles.state.movesTotal); // 19
console.log(tiles.state.squares['e4']);// `tiles.state.squares['e4']` - the e4 square, trimmed to the interesting bits
{
w: {
total: { movedTo: 2, occupiedFor: 13, captures: 0, losses: 0 },
byPiece: {
Pe: { movedTo: 2, occupiedFor: 13, captures: 0, losses: 0 },
// …15 more white pieces, all zero here
},
},
b: {
total: { movedTo: 0, occupiedFor: 0, captures: 0, losses: 0 },
// …same breakdown for each black piece under byPiece
},
}White's e-pawn (Pe) moved to e4 twice and then sat there for 13 half-moves in total — that's the whole story of e4 in our file. Built-in trackers explains every field.
Turning it into a picture
Numbers per square are nice but patterns become more obvious if you print them as a heatmap. generateHeatmap maps the state to one value per square, and printHeatmap renders a colored board in your terminal:
import { generateHeatmap, printHeatmap, TileHeatmapPresets } from 'chessalyzer/trackers';
const heatmapData = generateHeatmap(tiles.state, TileHeatmapPresets.TILE_OCC_ALL);
printHeatmap(heatmapData); // colored 8×8 board in your terminalTILE_OCC_ALL answers "how busy was each square?" — the percentage of half-moves a square had a piece on it. Underneath the colors, heatmapData is plain data ({ grid, min, max }); here's the actual grid for our file, with files a–h left to right and rank 8 on top:
a b c d e f g h
8 100.00 84.21 89.47 100.00 100.00 100.00 94.74 100.00
7 100.00 100.00 68.42 78.95 63.16 94.74 100.00 100.00
6 0.00 0.00 15.79 21.05 0.00 5.26 0.00 0.00
5 0.00 10.53 31.58 0.00 36.84 0.00 0.00 10.53
4 0.00 0.00 21.05 0.00 68.42 0.00 5.26 0.00
3 0.00 0.00 0.00 0.00 0.00 42.11 0.00 0.00
2 100.00 100.00 100.00 100.00 31.58 84.21 94.74 100.00
1 100.00 100.00 100.00 89.47 100.00 63.16 73.68 100.00Spot e4 at 68.42% (13 of 19 half-moves) and f3 at 42.11% — white's ill-fated first move in game two. Since heatmapData is just numbers, you can also feed it into any charting library you like. More in Heatmaps.