nytimes-games
An unofficial Python client for the New York Times Games APIs: Wordle, Connections, Strands, Spelling Bee, Letter Boxed and the Daily, Mini, Midi and Bonus crosswords, plus your own stats and game progress.
NYT doesn't publish documentation or an API spec for these endpoints. This
package wraps them in one client with typed, validated
Pydantic models, so you can build archives,
stats dashboards, bots or your own games without reverse engineering NYT's
APIs first. Optional extras add the nytg command line tool and a REST API.
Installation
pip install nytimes-games
The package installs as nytimes-games and is imported as nytgames.
Python 3.10 or newer is required.
Quick start
from nytgames import NYTGamesClient
client = NYTGamesClient()
client.wordle("2025-06-12").solution
client.connections("2025-06-12").categories
client.crossword("mini") # today's Mini
client.crossword("daily", "1993-11-21") # any Daily back to 1993
Your stats and game progress need your NYT session cookie:
client = NYTGamesClient(cookies="NYT-S=...")
stats = client.player_stats().stats
stats.wordle.calculatedStats.currentStreak
stats.connections.puzzles_won
stats.crossword_daily.dailyStats["monday"].avgTimeSeconds
What's available
Puzzles don't need cookies. Everything about you does.
| Game | Method | Available from | Cookies |
|---|---|---|---|
| Wordle | wordle(date) |
2021-06-19 | No |
| Connections | connections(date) |
2023-06-12 | No |
| Strands | strands(date) |
2024-03-04 | No |
| Spelling Bee | spelling_bee_puzzle(date) |
2018-05-06 | No |
| Letter Boxed | letter_boxed(date) |
2018-12-17 | No |
| Crossword | crossword(publish_type, date=None) |
Daily 1993-11-21, Mini 2014-08-21, Midi 2026-02-25, Bonus 1997 | No |
| Crossword schedule | crossword_oracle(publish_type) |
Current and next puzzle | No |
| Puzzle list | archive(game, date_start, date_end) |
IDs and dates for Wordle, Connections, Strands and the Daily, Mini and Midi | No |
| Crossword list | crossword_puzzles(publish_type, date_start=..., date_end=...) |
Daily, Mini and Bonus, with your progress when you have cookies | Optional |
| Crossword progress | crossword_game(puzzle_id, publish_type) |
Your saved game | Yes |
| Wordle progress | wordle_latest(puzzle_ids) |
Your saved games | Yes |
| Spelling Bee progress | spelling_bee_latest(puzzle_ids) |
Your saved games (up to 30 IDs) | Yes |
| Stats | player_stats() |
Every game you've played | Yes |
Dates are YYYY-MM-DD strings. publish_type is daily, mini, midi or
bonus, and date=None returns today's puzzle. NYT usually serves the next
day's puzzle a day early.
archive() is the quickest way to get puzzle IDs for a date range, for
example to check your progress on a month of puzzles:
midis = client.archive("crossword_midi", "2026-09-01", "2026-09-30")
client.crossword_game([p.id for p in midis], "midi") # up to 30 IDs per call
Spelling Bee extras:
from nytgames import spelling_bee_hints
puzzle = client.spelling_bee_puzzle("2026-10-03")
spelling_bee_hints(puzzle) # Spelling Bee Forum style hints: counts, pairs, points
client.spelling_bee_puzzles() # every puzzle on the game page (about two weeks)
Cookies
To get your NYT-S cookie, log in at nytimes.com, open your browser's
developer tools, and find the NYT-S cookie for .nytimes.com (Application
tab in Chrome, Storage tab in Firefox). Treat it like a password: it gives
access to your NYT account.
cookies can be:
- a
Cookieheader string:"NYT-S=...; nyt-a=..." - a dict:
{"NYT-S": "..."} - a list of cookie objects with
nameandvaluekeys, such as a JSON export from the Cookie-Editor browser extension
Errors
HTTP errors from NYT are raised as NYTGamesHTTPError, a subclass of
requests.HTTPError:
| Exception | When |
|---|---|
NYTGamesAuthenticationError |
401 or 403, usually a missing or expired NYT-S cookie |
NYTGamesNotFoundError |
404, for example a date with no puzzle |
NYTGamesHTTPError |
any other HTTP error |
NYTGamesParseError |
an NYT page didn't contain the expected game data (a ValueError) |
from nytgames import NYTGamesNotFoundError
try:
client.wordle("1900-01-01")
except NYTGamesNotFoundError:
print("No puzzle that day")
Models
Every method returns Pydantic models from nytgames.models. Fields NYT adds
later are kept rather than rejected, so new NYT fields don't break your code.
Use .model_dump() to get plain dicts, and by_alias=True to keep NYT's
original keys, such as "Queen Bee" in the Spelling Bee ranks.
Command line
The optional cli extra installs nytg:
pipx install "nytimes-games[cli]" # or: pip install "nytimes-games[cli]"
nytg wordle # today's Wordle, without the answer
nytg wordle yesterday --answers
nytg connections friday -a # the groups, in their colors
nytg strands 2025-06-12
nytg bee --hints # Spelling Bee Forum style hints
nytg letter-boxed
nytg crossword mini # the grid and clues
nytg crossword daily 1993-11-21 --answers
Answers are hidden unless you pass --answers, in every output format.
Dates can be YYYY-MM-DD, today, yesterday, tomorrow or a weekday, and
first for the first puzzle in nytg archive.
Your stats and history
Log in once with your NYT-S cookie (see Cookies):
nytg auth login # paste the cookie; it's checked, then saved
nytg auth status
nytg stats # every game at a glance
nytg stats crossword # averages, bests and streaks by weekday
nytg today # which of today's games you've played
nytg history crossword --from 2026-01-01 -f csv > solves.csv
nytg history wordle --from monday
nytg history bee
Cookies are read from --cookies, then the NYT_COOKIES environment
variable, then the active profile.
Archiving
nytg archive connections --from first --out puzzles/
saves each date as puzzles/connections/YYYY-MM-DD.json. Run it again to
resume: saved dates are skipped. Games: wordle, connections, strands,
spelling-bee, letter-boxed, crossword-daily, crossword-mini and
crossword-midi.
Output formats
Every command takes --format (-f), like gcloud:
| Format | Output |
|---|---|
table |
Tables and grids (the default) |
json, yaml |
All the data |
csv |
One row per item, nested fields as dotted columns |
value(FIELD,...) |
Tab separated values for scripts, e.g. value(categories[0].title) |
nytg wordle --answers -f "value(solution)"
nytg stats -f json | jq '.[] | select(.game == "Wordle")'
Profiles and settings
Settings are saved per profile in ~/.config/nytg/config.ini (readable only
by you), similar to gcloud configurations:
nytg config set format json # default output format for this profile
nytg config list
nytg --profile alice auth login # a second NYT account
nytg config profiles activate alice
nytg config profiles list
--profile or NYTG_PROFILE picks a profile for one command. Run
nytg --install-completion for shell completion.
Building your own command line
nytgames.cli.extension lets you build a command line with every nytg
command plus your own, sharing its root options (--profile, --cookies,
--format), output formats and error messages:
import typer
from nytgames.cli.extension import FormatOption, create_app, emit, get_client, run
app = create_app(name="mytool", help="My NYT tools.", version="1.0.0")
db = typer.Typer(help="Query my archive.")
app.add_typer(db, name="db")
@db.command("midis")
def midis(fmt: FormatOption = None) -> None:
"""September's Midi crosswords."""
puzzles = get_client().archive("crossword_midi", "2026-09-01", "2026-09-30")
emit([{"date": p.print_date, "by": p.byline} for p in puzzles], fmt)
def main() -> None: # point your [project.scripts] entry here
run(app)
Each create_app() call returns an independent app. emit(data, fmt, table) prints JSON-compatible data in the requested format, with an optional
function that renders the table format. get_client() returns a client with
the cookies nytg would use. The other modules in nytgames.cli are
internal.
REST API
The optional api extra serves everything as a REST API with
FastAPI, including interactive docs at
/docs.
pip install "nytimes-games[api]"
uvicorn nytgames.api:app
To customize it, write your own main.py:
from nytgames.api import create_app
app = create_app(title="My NYT Games API") # any FastAPI settings
Or mount the routes in an existing FastAPI app:
from fastapi import FastAPI
from nytgames.api import add_exception_handlers, router
app = FastAPI()
app.include_router(router, prefix="/nyt")
add_exception_handlers(app) # NYT errors become 404s and 403s instead of 500s
By default each request is made with the cookies sent to the API:
curl -H "Cookie: NYT-S=..." http://localhost:8000/player/stats
To use your own cookies for every request instead, override the client:
from nytgames import NYTGamesClient
from nytgames.api import get_client
app.dependency_overrides[get_client] = lambda: NYTGamesClient(cookies="NYT-S=...")
Anyone who can reach that API can then see your stats and progress, so keep it private.
examples/api has a complete main.py and Dockerfile for
running your own instance in a container.
Endpoints
| Route | NYT endpoint |
|---|---|
GET /archive/{game}/{date_start}/{date_end} |
svc/games/v1/archive/{game}/{date_start}/{date_end} |
GET /connections/{date} |
svc/connections/v2/{date}.json |
GET /crosswords/daily/today |
svc/crosswords/v6/puzzle/daily.json |
GET /crosswords/daily/{date} |
svc/crosswords/v6/puzzle/daily/{date}.json |
GET /crosswords/mini/today |
svc/crosswords/v6/puzzle/mini.json |
GET /crosswords/mini/{date} |
svc/crosswords/v6/puzzle/mini/{date}.json |
GET /crosswords/midi/today |
svc/crosswords/v6/puzzle/midi.json |
GET /crosswords/midi/{date} |
svc/crosswords/v6/puzzle/midi/{date}.json |
GET /crosswords/bonus/{date} |
svc/crosswords/v6/puzzle/bonus/{date}.json |
GET /crosswords/puzzles |
svc/crosswords/v3/puzzles.json |
GET /crosswords/oracle/{publish_type} |
svc/crosswords/v2/oracle/{publish_type}.json |
GET /crosswords/game/{game_id}?publish_type=daily |
svc/games/state/crossword_{publish_type}/latests |
GET /letter-boxed/{date} |
svc/letter-boxed/v1/{date}.json |
GET /player/stats |
svc/games/state/wordleV2/latests?puzzle_ids=0 |
GET /spelling-bee |
Scraped from puzzles/spelling-bee |
GET /spelling-bee/latest |
svc/games/state/spelling_bee/latests |
GET /spelling-bee/{date} |
svc/spelling-bee/v1/{date}.json |
GET /spelling-bee/{date}/hints |
Computed from the puzzle above |
GET /strands/{date} |
svc/strands/v2/{date}.json |
GET /wordle/latest |
svc/games/state/wordleV2/latests |
GET /wordle/{date} |
svc/wordle/v2/{date}.json |
NYT errors are returned with NYT's status code, for example 404 for a date with no puzzle.
Contributing
NYT changes these APIs without notice, so bug reports with the failing date and error are very welcome. See CONTRIBUTING.md to set up a development environment.
License
MIT. This project is not affiliated with or endorsed by The New York Times. NYT puzzles are copyrighted by The New York Times; please respect their terms of service and don't republish puzzle content.
Metadata
Release files for nytimes-games 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nytimes_games-0.6.0.tar.gz | 53.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nytimes_games-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 99.0 kB
Release files / nytimes_games-0.6.0.tar.gz
| Download URL | nytimes_games-0.6.0.tar.gz |
|---|---|
| Size | 53.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3e0d3ddce6756e49b79af998451fdf79ef3bd26bd0321730a3bca29fb549195f
|
|
BLAKE2b-256 checksum How to use checksums |
9465b108527f19604e3007267c2b11e8f51e68c1646aaa02f5d26e30bf9046e3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency logRelease files / nytimes_games-0.6.0-py3-none-any.whl
| Download URL | nytimes_games-0.6.0-py3-none-any.whl |
|---|---|
| Size | 45.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
75b3040d8e66f717329e7facca8fc7c6786cd93b702a5c56b729e925b9e1950b
|
|
BLAKE2b-256 checksum How to use checksums |
48f65e3bad7ea78bb8452f9352f217643881ed6680d400a4b6acd384e83e365a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency log