Download free games from itch.io programmatically.
No API key. No browser required for most games. No GUI.
npm install itchio-downloaderconst { downloadGame } = require('itchio-downloader');
const result = await downloadGame({
itchGameUrl: 'https://baraklava.itch.io/manic-miners',
});
// Downloads a 1 GB game via direct HTTP — no browser neededThere's no official API for downloading free itch.io games. The itch desktop app requires a GUI. Butler requires developer access. This library gives you a single function call or CLI command that just works.
Tested on games from 2.6 MB to 1.9 GB. 187 automated tests. Strict TypeScript. Zero lint warnings.
| Direct HTTP | Downloads free game builds over HTTP — no browser binary needed |
| HTML5 Web Games | Auto-detect browser-only games and save them for offline play; --html5 selects this mode immediately |
| Resume Downloads | Resume interrupted downloads using HTTP Range headers with --resume |
| Cookie Caching | Reuse itch.io session cookies and CSRF tokens for 30 minutes |
| Size Verification | Validate Content-Length matches actual bytes downloaded on every path |
| Platform Selection | Choose a Windows, Mac, or Linux API upload with --platform |
| API Key Support | Optional authenticated downloads via itch.io API |
| Batch & Concurrent | Download multiple games with configurable concurrency and rate limiting |
| Config Files | Run validated JSON or YAML game lists with shared defaults and CLI overrides |
| Collections | Fetch every game from a collection URL in one command |
| Game Jams | Download all entries from a game jam with --jam |
| In-Memory | Download to a Buffer instead of disk |
| Progress Tracking | Real-time progress bar in CLI, onProgress callback in library |
| Retries | Exponential backoff on failure |
| Metadata | Saves game metadata JSON alongside downloads |
| Puppeteer Fallback | Separately installed, last-resort browser fallback for Node.js 22.12+ |
downloadGame(params)
1. API key provided? --> Authenticated API download
2. --html5 flag? --> Scrape web game assets
3. Free game? --> Direct HTTP (CSRF --> download page --> CDN URL)
4. Web-only game? --> Auto-detect and scrape HTML5 assets
5. All else fails? --> Puppeteer fallback (if installed)
Most free games resolve at step 3. Puppeteer is not installed by default. On Node.js 22.12 or newer, install it separately only if you need the last-resort browser fallback.
Core downloads require Node.js ^20.19.0, ^22.12.0, or >=23. The optional
Puppeteer fallback requires Node.js 22.12 or newer.
# As a library
npm install itchio-downloader
# As a global CLI
npm install -g itchio-downloader
# With pnpm or yarn
pnpm add itchio-downloader
yarn add itchio-downloader
# Optional browser fallback (Node.js 22.12+)
npm install puppeteer@^25.11.0
# If the downloader CLI was installed globally
npm install -g puppeteer@^25.11.0
# Arch Linux (AUR) — https://aur.archlinux.org/packages/itchio-downloader
yay -S itchio-downloader
# Optional last-resort browser fallback on Arch
yay -S puppeteer chromium# Download by URL
itchio-downloader --url "https://baraklava.itch.io/manic-miners"
# Download by name + author
itchio-downloader --name "manic-miners" --author "baraklava" --downloadDirectory ./games
# HTML5 web games are auto-detected
itchio-downloader --url "https://ncase.itch.io/wbwwb"
# Or select HTML5 mode immediately
itchio-downloader --url "https://ncase.itch.io/wbwwb" --html5
# Choose a platform build
itchio-downloader --url "https://dev.itch.io/game" --platform linux
# Resume an interrupted download
itchio-downloader --url "https://dev.itch.io/large-game" --resume
# Download all entries from a game jam
itchio-downloader --jam "https://itch.io/jam/gmtk-2023" --concurrency 3
# Download a collection with rate limiting
itchio-downloader --collection "https://itch.io/c/123/my-collection" --concurrency 2 --delay 1000
# Download a reusable JSON or YAML game list
itchio-downloader --config ./games.yaml
# Explicit CLI options override config values for every entry
itchio-downloader --config ./games.json --downloadDirectory ./games --concurrency 3
# With API key and retries
itchio-downloader --url "https://dev.itch.io/game" --apiKey "your-key" --retries 3
# Disable cookie caching
itchio-downloader --url "https://dev.itch.io/game" --noCookieCacheSee docs/CLI.md for the full option reference.
const { downloadGame } = require('itchio-downloader');
// By URL — no API key needed
const result = await downloadGame({
itchGameUrl: 'https://vfqd.itch.io/terra-nil',
downloadDirectory: './games',
});
console.log(result.filePath); // './games/Terra Nil 0.41 Windows.zip'
// By name and author
const result2 = await downloadGame({
name: 'manic-miners',
author: 'baraklava',
});Download browser-only games (game jams, HTML5 embeds) with their discovered assets for offline play:
const result = await downloadGame({
itchGameUrl: 'https://ncase.itch.io/wbwwb',
html5: true,
downloadDirectory: './games',
});
console.log(result.html5Assets);
// ['css/game.css', 'js/lib/pixi.min.js', 'sprites/bg.png', ...]
// Open ./games/wbwwb/index.html to play offlineLarge single-file HTML5 games are streamed directly to disk. When itch.io compresses a response, verification uses the decoded byte count without mistaking the compressed HTTP length for the saved file size.
The html5 option selects this path immediately. Without it, HTML5 games are
auto-detected and the initial page response is reused, so detection does not
add another request to itch.io.
Download all entries from an itch.io game jam:
const { downloadJam } = require('itchio-downloader');
const results = await downloadJam('https://itch.io/jam/gmtk-2023', null, {
concurrency: 3,
downloadDirectory: './jam-games',
});Large downloads can be resumed if interrupted. Partial data is saved to a .part file and continues from where it left off:
const result = await downloadGame({
itchGameUrl: 'https://baraklava.itch.io/manic-miners',
resume: true,
});
console.log(result.resumed); // true if continued from partial
console.log(result.sizeVerified); // true if Content-Length matched
console.log(result.bytesDownloaded); // total bytes writtenSession cookies and CSRF tokens are cached automatically (30-min TTL) so subsequent downloads can reuse the same itch.io session:
// Disable caching or customize the directory
await downloadGame({
itchGameUrl: 'https://dev.itch.io/game',
noCookieCache: true,
cookieCacheDir: '/tmp/cache',
});
// Manage the cache programmatically
const { getCachedCookies, clearCachedCookies } = require('itchio-downloader');
const cached = await getCachedCookies('https://dev.itch.io/game');
await clearCachedCookies(); // clear allawait downloadGame({
itchGameUrl: 'https://baraklava.itch.io/manic-miners',
onProgress: ({ bytesReceived, totalBytes, fileName }) => {
if (totalBytes) {
const pct = ((bytesReceived / totalBytes) * 100).toFixed(1);
console.log(`${fileName}: ${pct}%`);
}
},
});Platform Selection
await downloadGame({
itchGameUrl: 'https://dev.itch.io/game',
platform: 'linux', // 'windows', 'linux', or 'osx'
apiKey: 'your-key',
});In-Memory Download
const result = await downloadGame({
itchGameUrl: 'https://baraklava.itch.io/manic-miners',
apiKey: 'your-key',
inMemory: true,
});
console.log(result.fileBuffer); // Buffer containing the fileBatch Downloads
await downloadGame(
[
{ name: 'manic-miners', author: 'baraklava' },
{ itchGameUrl: 'https://dev.itch.io/game' },
],
{ concurrency: 2, delayBetweenMs: 1000 },
);| Parameter | Type | Default | Description |
|---|---|---|---|
itchGameUrl |
string |
-- | Direct URL to the game |
name |
string |
-- | Game name (use with author) |
author |
string |
-- | Author's username |
apiKey |
string |
ITCH_API_KEY env |
API key for authenticated downloads |
downloadDirectory |
string |
~/downloads |
Where to save files |
desiredFileName |
string |
-- | Custom base name; the downloaded extension is kept |
inMemory |
boolean |
false |
Download to Buffer instead of disk |
html5 |
boolean |
false |
Select HTML5 mode immediately; web-only games are auto-detected |
platform |
string |
-- | Preferred API upload: windows, linux, osx |
resume |
boolean |
false |
Resume interrupted downloads (Range headers) |
noCookieCache |
boolean |
false |
Disable automatic cookie caching |
cookieCacheDir |
string |
system tmpdir | Directory for the cookie cache |
writeMetaData |
boolean |
true |
Save metadata JSON alongside download |
retries |
number |
0 |
Retry attempts on failure |
retryDelayMs |
number |
500 |
Base delay for exponential backoff (ms) |
navigationTimeoutMs |
number |
30000 |
Puppeteer page navigation timeout (ms) |
fileWaitTimeoutMs |
number |
30000 |
Puppeteer download-file wait timeout (ms) |
parallel |
boolean |
false |
If true on any batch item, run the whole batch concurrently |
onProgress |
function |
-- | ({ bytesReceived, totalBytes, fileName }) => void |
For array downloads, the second downloadGame argument can be a concurrency
number or { concurrency, delayBetweenMs }.
type DownloadGameResponse = {
status: boolean; // true if download succeeded
message: string; // human-readable result
failReason?: string; // structured reason for supported failure paths
filePath?: string; // path to downloaded file
fileBuffer?: Buffer; // file contents (inMemory mode)
metadataPath?: string; // path to metadata JSON
metaData?: IItchRecord; // game metadata object
html5Assets?: string[]; // downloaded asset paths (html5 mode)
httpStatus?: number; // HTTP status code on failure
sizeVerified?: boolean; // true if Content-Length matched actual bytes
bytesDownloaded?: number; // total bytes downloaded
resumed?: boolean; // true if download was resumed from .part file
};- HTTP 403: the page may be private, restricted, or blocked by itch.io. Confirm it opens in a logged-out browser; this tool does not bypass access controls.
- HTTP 404: check the URL. The page may have been renamed, removed, or unpublished.
- HTML5 game: retry with
--html5to explicitly select offline web-game downloading. Large single-file games can take time even when no additional assets are listed. - Browser fallback unavailable: on Node.js 22.12+, install it with
npm install puppeteer@^25.11.0. On Arch, install both pieces withyay -S puppeteer chromium. A browser cannot make a private, paid, or HTML5-only build downloadable as a desktop archive. - Sessions: cookie caching is enabled by default. Avoid
--noCookieCacheunless a fresh unauthenticated session is intentional. - Debugging: prefix the command with
DEBUG_DOWNLOAD_GAME=trueand remove credentials before sharing its output in an issue.
git clone https://github.com/Wal33D/itchio-downloader.git
cd itchio-downloader
pnpm install
pnpm test # 187 tests
pnpm run build # compile TypeScript
pnpm run lint # ESLint (zero warnings)| API Reference | Functions, types, and exports |
| CLI Reference | All command-line options |
| Advanced Usage | Resume, cookies, concurrency, HTML5 |
| Installation | Setup requirements |
| Debugging | Troubleshooting tips |
| Roadmap | Planned improvements |
| Changelog | Release history |
| Contributing | Contribution guidelines |
Only download free games and follow the itch.io Terms of Service. Don't bypass payment restrictions. This project isn't affiliated with or endorsed by itch.io.