Skip to content
dblike edited this page Mar 23, 2026 · 2 revisions

Games API

Export and stream games played on Lichess.

Namespace: LichessSharp.Api.Contracts, LichessSharp.Models.Games Access: client.Games


Single Game Export

ExportAsync

Export a single game by ID in JSON format.

Task<GameJson> ExportAsync(
    string gameId,
    ExportGameOptions? options = null,
    CancellationToken cancellationToken = default)

Parameters:

Name Type Description
gameId string The game ID (8 characters)
options ExportGameOptions? Export options

ExportGameOptions:

Property Type Description
Moves bool? Include moves (default true)
PgnInJson bool? Include PGN in JSON response
Tags bool? Include PGN tags
Clocks bool? Include clock comments
Evals bool? Include analysis evaluations
Accuracy bool? Include accuracy percentages
Opening bool? Include opening info
Literate bool? Insert textual annotations
Players string? URL of a text file with usernames

Example:

using var client = new LichessClient();

var game = await client.Games.ExportAsync("AbCdEfGh", new ExportGameOptions
{
    Moves = true,
    Clocks = true,
    Evals = true,
    Opening = true
});

Console.WriteLine($"Game ID: {game.Id}");
Console.WriteLine($"White: {game.Players?.White?.User?.Name} ({game.Players?.White?.Rating})");
Console.WriteLine($"Black: {game.Players?.Black?.User?.Name} ({game.Players?.Black?.Rating})");
Console.WriteLine($"Result: {game.Winner ?? "draw"}");
Console.WriteLine($"Moves: {game.Moves}");
Console.WriteLine($"Opening: {game.Opening?.Name}");

if (game.Clock != null)
{
    Console.WriteLine($"Time Control: {game.Clock.Initial / 60}+{game.Clock.Increment}");
}

GetPgnAsync

Export a single game in PGN format.

Task<string> GetPgnAsync(
    string gameId,
    ExportGameOptions? options = null,
    CancellationToken cancellationToken = default)

Example:

using var client = new LichessClient();

var pgn = await client.Games.GetPgnAsync("AbCdEfGh", new ExportGameOptions
{
    Clocks = true,
    Evals = true
});

Console.WriteLine(pgn);
// Outputs:
// [Event "Rated Blitz game"]
// [Site "https://lichess.org/AbCdEfGh"]
// [White "Player1"]
// [Black "Player2"]
// ...
// 1. e4 { [%clk 3:00:00] } e5 { [%clk 3:00:00] } ...

GetCurrentGameByUserAsync

Get the ongoing game, or last game, of a user.

Task<GameJson> GetCurrentGameByUserAsync(
    string username,
    ExportGameOptions? options = null,
    CancellationToken cancellationToken = default)

Example:

using var client = new LichessClient();

try
{
    var game = await client.Games.GetCurrentGameByUserAsync("DrNykterstein");
    Console.WriteLine($"Current game: {game.Id}");
    Console.WriteLine($"Status: {game.Status}");
}
catch (LichessApiException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
    Console.WriteLine("User is not currently playing");
}

Streaming Games

StreamUserGamesAsync

Stream all games of a user.

IAsyncEnumerable<GameJson> StreamUserGamesAsync(
    string username,
    ExportUserGamesOptions? options = null,
    CancellationToken cancellationToken = default)

ExportUserGamesOptions:

Property Type Description
Since DateTimeOffset? Only games played since
Until DateTimeOffset? Only games played until
Max int? Maximum number of games
Vs string? Only games against this opponent
Rated bool? Only rated or casual games
PerfType string? Only games of this variant
Color string? Only games as this color
Analysed bool? Only analysed games
Ongoing bool? Include ongoing games
Finished bool? Include finished games
Sort string? "dateAsc" or "dateDesc"
Moves bool? Include moves
PgnInJson bool? Include PGN
Tags bool? Include PGN tags
Clocks bool? Include clock comments
Evals bool? Include evaluations
Accuracy bool? Include accuracy
Opening bool? Include opening info

Example - Export all blitz games:

using var client = new LichessClient();

var options = new ExportUserGamesOptions
{
    PerfType = "blitz",
    Max = 100,
    Moves = true,
    Opening = true
};

await foreach (var game in client.Games.StreamUserGamesAsync("DrNykterstein", options))
{
    Console.WriteLine($"{game.Id}: {game.Players?.White?.User?.Name} vs {game.Players?.Black?.User?.Name}");
    Console.WriteLine($"  Opening: {game.Opening?.Name}");
    Console.WriteLine($"  Result: {game.Winner ?? "draw"}");
}

Example - Games in a date range:

var options = new ExportUserGamesOptions
{
    Since = DateTimeOffset.UtcNow.AddMonths(-1),
    Until = DateTimeOffset.UtcNow,
    Rated = true,
    Sort = "dateDesc"
};

await foreach (var game in client.Games.StreamUserGamesAsync("username", options))
{
    Console.WriteLine($"{game.CreatedAt}: {game.Id}");
}

StreamByIdsAsync

Export multiple games by their IDs.

IAsyncEnumerable<GameJson> StreamByIdsAsync(
    IEnumerable<string> gameIds,
    ExportGameOptions? options = null,
    CancellationToken cancellationToken = default)

Example:

using var client = new LichessClient();

var gameIds = new[] { "game1id1", "game2id2", "game3id3" };

await foreach (var game in client.Games.StreamByIdsAsync(gameIds))
{
    Console.WriteLine($"{game.Id}: {game.Status}");
}

StreamByUsersAsync

Stream ongoing games of specified users in real-time.

IAsyncEnumerable<GameJson> StreamByUsersAsync(
    IEnumerable<string> userIds,
    bool withCurrentGames = false,
    CancellationToken cancellationToken = default)

Parameters:

Name Type Description
userIds IEnumerable User IDs (up to 300)
withCurrentGames bool Include games already in progress

Example:

using var client = new LichessClient();
using var cts = new CancellationTokenSource();

var topPlayers = new[] { "DrNykterstein", "Hikaru", "penguingm1" };

Console.WriteLine("Watching for games...");

await foreach (var game in client.Games.StreamByUsersAsync(topPlayers, withCurrentGames: true, cts.Token))
{
    Console.WriteLine($"Game: {game.Id}");
    Console.WriteLine($"  {game.Players?.White?.User?.Name} vs {game.Players?.Black?.User?.Name}");
    Console.WriteLine($"  Status: {game.Status}");
}

StreamGameMovesAsync

Stream a single game's moves in real-time.

IAsyncEnumerable<MoveStreamEvent> StreamGameMovesAsync(
    string gameId,
    CancellationToken cancellationToken = default)

Example:

using var client = new LichessClient();
using var cts = new CancellationTokenSource();

await foreach (var evt in client.Games.StreamGameMovesAsync("AbCdEfGh", cts.Token))
{
    Console.WriteLine($"FEN: {evt.Fen}");
    Console.WriteLine($"Last Move: {evt.LastMove}");

    if (evt.WhiteTime.HasValue)
        Console.WriteLine($"White Time: {evt.WhiteTime}ms");
    if (evt.BlackTime.HasValue)
        Console.WriteLine($"Black Time: {evt.BlackTime}ms");
}

Watching Multiple Games

StreamByIdsAsync (with stream ID)

Create a stream to watch multiple games with add/remove capability.

IAsyncEnumerable<GameStreamEvent> StreamByIdsAsync(
    string streamId,
    IEnumerable<string> gameIds,
    CancellationToken cancellationToken = default)

AddGameIdsToStreamAsync

Add games to an existing stream.

Task AddGameIdsToStreamAsync(
    string streamId,
    IEnumerable<string> gameIds,
    CancellationToken cancellationToken = default)

Example:

using var client = new LichessClient();
using var cts = new CancellationTokenSource();

var streamId = Guid.NewGuid().ToString();
var initialGames = new[] { "game1234", "game5678" };

// Start watching
var watchTask = Task.Run(async () =>
{
    await foreach (var evt in client.Games.StreamByIdsAsync(streamId, initialGames, cts.Token))
    {
        Console.WriteLine($"Game {evt.Id}: {evt.Fen}");
    }
});

// Add more games later
await Task.Delay(5000);
await client.Games.AddGameIdsToStreamAsync(streamId, new[] { "newgame1" });

await watchTask;

User's Games

GetOngoingGamesAsync

Get ongoing games of the authenticated user.

Task<IReadOnlyList<OngoingGame>> GetOngoingGamesAsync(
    int count = 9,
    CancellationToken cancellationToken = default)

Example:

using var client = new LichessClient(token);

var games = await client.Games.GetOngoingGamesAsync(count: 20);

Console.WriteLine($"You have {games.Count} ongoing games:");
foreach (var game in games)
{
    Console.WriteLine($"  {game.GameId}: vs {game.Opponent?.Username} ({game.Speed})");
    Console.WriteLine($"    Your turn: {game.IsMyTurn}");
    Console.WriteLine($"    Time left: {game.SecondsLeft}s");
}

StreamBookmarkedGamesAsync

Stream all bookmarked games.

Required Scope: OAuth authentication

IAsyncEnumerable<GameJson> StreamBookmarkedGamesAsync(
    ExportBookmarksOptions? options = null,
    CancellationToken cancellationToken = default)

Example:

using var client = new LichessClient(token);

await foreach (var game in client.Games.StreamBookmarkedGamesAsync())
{
    Console.WriteLine($"{game.Id}: {game.Players?.White?.User?.Name} vs {game.Players?.Black?.User?.Name}");
}

Import/Export

ImportAsync

Import a game from PGN.

Task<ImportGameResponse> ImportAsync(
    string pgn,
    CancellationToken cancellationToken = default)

Example:

using var client = new LichessClient(token);

var pgn = @"
[Event ""Casual game""]
[White ""Player1""]
[Black ""Player2""]

1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O *
";

var result = await client.Games.ImportAsync(pgn);

Console.WriteLine($"Imported game: {result.Id}");
Console.WriteLine($"URL: {result.Url}");

ExportImportedGamesAsync

Export all games you have imported in PGN format.

Required Scope: OAuth authentication

Task<string> ExportImportedGamesAsync(CancellationToken cancellationToken = default)

Example:

using var client = new LichessClient(token);

var allImportedPgn = await client.Games.ExportImportedGamesAsync();

// Save to file
await File.WriteAllTextAsync("my-imported-games.pgn", allImportedPgn);

Game Chat

GetSpectatorChatAsync

Fetch the messages posted in the public spectator chat of a game. No authentication required.

Task<IReadOnlyList<ChatMessage>> GetSpectatorChatAsync(
    string gameId,
    CancellationToken cancellationToken = default)

Example:

using var client = new LichessClient();

var messages = await client.Games.GetSpectatorChatAsync("AbCdEfGh");

foreach (var msg in messages)
{
    Console.WriteLine($"{msg.User}: {msg.Text}");
}

Note: This returns the public spectator chat. For the private player chat (between the 2 players), use Board.GetChatAsync or Bot.GetChatAsync instead.


See Also

Clone this wiki locally