akinator-client
v1.3.0
Published
A modern, fully typed Node.js client for Akinator that actually works. Bypasses Cloudflare 403, with proxy, retry, session persistence, 16 languages and Discord bot example.
Maintainers
Readme
akinator-client
A modern, fully typed Node.js client for the Akinator game.
Contents
- Features
- Requirements
- Quick Start
- API Reference
- Full Example
- Languages
- Themes
- FAQ
- Contributing
- Roadmap
- License
Features
- 🚀 Fully typed TypeScript API
- 🌍 16 supported languages
- 🎭 3 game themes
- 🔄 Complete game lifecycle (start, answer, back, continue, win)
- ☁️ Handles Akinator's current web protection flow
- 🔁 Automatic retry on network errors
- 🌐 HTTP proxy support
- 👶 Child mode support
- 💾 Session persistence (save/load games)
Requirements
- Node.js >= 18
Quick Start
npm install akinator-clientCreate a new client and start a game:
import { AkinatorClient, Languages, Answers, Themes } from "akinator-client";
const akinator = new AkinatorClient({
language: Languages.English,
theme: Themes.Character,
});
// Start the game
const first = await akinator.start();
console.log(first.question); // "Is your character real?"
// Answer questions
const result = await akinator.answer(Answers.Yes);
console.log(result.question);
// Go back if needed
await akinator.back();
// When Akinator guesses
if (result.won) {
console.log(akinator.winResult.name);
await akinator.submitWin();
}API Reference
import {
AkinatorClient,
Languages,
Themes,
Answers,
} from "akinator-client";Constructor
new AkinatorClient(options?)You can use the enum or the string code directly:
// Using enum
new AkinatorClient({ language: Languages.English })
// Using string code
new AkinatorClient({ language: "en" })| Option | Type | Default | Description |
|--------|------|---------|-------------|
| language | Languages | Languages.Portuguese | Game language |
| theme | Themes | Themes.Character | Game theme |
| childMode | boolean | false | Enable child mode (no explicit content) |
| proxy | string | - | HTTP proxy URL (e.g. http://proxy:8080) |
| retries | number | 3 | Number of retries on network errors |
| ua | string | Chrome 131 UA | Override the User-Agent header |
| scraperApiKey | string | - | ScraperAPI key. Routes requests through their sync API and makes continue() work past the anti-bot check (see continue() note) |
| scraperApiSession | number | random | Sticky IP session number used with scraperApiKey |
Methods
| Method | Returns | Throws | Description |
|--------|---------|--------|-------------|
| start() | Promise<AnswerResult> | Theme not available, HTTP error | Start a new game |
| answer(answer) | Promise<AnswerResult> | Game not started, already guessed | Answer the current question |
| back() | Promise<AnswerResult> | Game not started, first question | Go back to the previous question |
| continue() | Promise<AnswerResult> | Game not started, no guess | Continue after a wrong guess |
| submitWin() | Promise<void> | Game not started, no guess | Confirm a correct guess |
Note on
continue(): Akinator's/excludeendpoint (used bycontinue()) checks the client with an anti-bot script ("Vital API blocked" / Cloudflare). A plain HTTP client with a mismatched TLS fingerprint is served an HTML challenge instead of JSON, although a real browser passes. Route requests through a browser-aware service to makecontinue()work:// ScraperAPI sync API (simplest) new AkinatorClient({ scraperApiKey: "YOUR_SCRAPERAPI_KEY" }) // ScraperAPI proxy with a sticky IP session new AkinatorClient({ proxy: "http://scraperapi.session_number=123456:[email protected]:8001", })Without a key/proxy,
continue()throws a descriptive error; keep playing with a freshstart()instead (see issue #3).
Properties
| Property | Type | Description |
|----------|------|-------------|
| question | string | Current question |
| step | number | Question number (0-indexed) |
| progression | number | Progress (0-100) |
| won | boolean | Whether Akinator guessed correctly |
| ko | boolean | Whether Akinator gave up |
| started | boolean | Whether the game has started |
| winResult | WinResult | Character data (available when won is true) |
Types
interface AnswerResult {
won: boolean;
ko: boolean;
akitude: string; // Akinator's current reaction/expression
step: number;
progression: number;
question: string;
answers: string[];
}
interface WinResult {
propositionId: number;
basePropositionId: number;
submittedBy: string;
name: string;
pictureUrl: string;
description: string;
}Full Example
import { AkinatorClient, Languages, Answers, Themes } from "akinator-client";
import readline from "readline";
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
const ask = (q) => new Promise((r) => rl.question(q, r));
const akinator = new AkinatorClient({
language: Languages.English,
theme: Themes.Character,
});
console.log("Starting game...");
await akinator.start();
console.log(`\n${akinator.question}\n`);
while (!akinator.won && !akinator.ko) {
console.log("0 - Yes | 1 - No | 2 - Don't know | 3 - Probably yes | 4 - Probably no | b - Back");
const input = await ask("\nAnswer: ");
if (input.trim().toLowerCase() === "b") {
const prev = await akinator.back();
console.log(`\n${prev.question}\n`);
continue;
}
const idx = parseInt(input, 10);
if (isNaN(idx) || idx < 0 || idx > 4) continue;
const answers = [Answers.Yes, Answers.No, Answers.IDontKnow, Answers.Probably, Answers.ProbablyNot];
const result = await akinator.answer(answers[idx]);
console.log(`\n(${result.step}/100 | ${result.progression.toFixed(1)}%) ${result.question}\n`);
}
if (akinator.ko) {
console.log("Akinator couldn't guess! You won!");
} else {
const win = akinator.winResult;
console.log(`Akinator guessed: ${win.name}`);
console.log(`Description: ${win.description}`);
const confirm = await ask("\nCorrect? (y/n): ");
if (confirm.trim().toLowerCase() === "y") {
await akinator.submitWin();
console.log("Confirmed!");
} else {
console.log("\nStarting a new game (continue() needs a scraperApiKey or browser-aware proxy)\n");
await akinator.start();
await ask("\nAsk your next character!\n");
}
}
rl.close();Run with: npx tsx example.js
Languages
| Code | Language | Available Themes |
|------|----------|------------------|
| en | English | Character, Animals, Objects |
| fr | Français | Character, Animals, Objects |
| de | Deutsch | Character, Animals |
| es | Español | Character, Animals |
| it | Italiano | Character, Animals |
| jp | 日本語 | Character, Animals |
| pt | Português | Character |
| ar | العربية | Character |
| cn | 中文 | Character |
| il | עברית | Character |
| kr | 한국어 | Character |
| nl | Nederlands | Character |
| pl | Polski | Character |
| ru | Русский | Character |
| tr | Türkçe | Character |
| id | Bahasa Indonesia | Character |
Themes
| Theme | ID | Description |
|-------|-----|-------------|
| Themes.Character | 1 | Guess a character (default) |
| Themes.Objects | 2 | Guess an object |
| Themes.Animals | 14 | Guess an animal |
FAQ
Does this work behind Cloudflare?
Yes. The library uses got-scraping to handle Akinator's current web protection flow automatically during the game.
Can I use proxies?
Yes. Pass a proxy URL in the constructor:
new AkinatorClient({ proxy: "http://proxy:8080" })To bypass the anti-bot check that protects continue() after a win, route through a browser-aware service such as ScraperAPI. Use either the sync API key or an HTTP proxy with a sticky IP session:
// Sync API (each request goes through api.scraperapi.com)
new AkinatorClient({ scraperApiKey: "YOUR_SCRAPERAPI_KEY" })
// HTTP proxy with sticky session on ScraperAPI's port 8001
new AkinatorClient({
proxy: "http://scraperapi.session_number=123456:[email protected]:8001",
})Each ScraperAPI request against pt.akinator.com costs 1 credit; a full game with a continue() uses roughly 15-25 credits. No Cloudflare/Turnstile bypass is triggered on this domain.
Can I resume a game?
Yes! Use toJSON() and fromJSON() to save and restore sessions:
// Save
const data = akinator.toJSON();
fs.writeFileSync("session.json", JSON.stringify(data));
// Load
const saved = JSON.parse(fs.readFileSync("session.json", "utf8"));
const restored = AkinatorClient.fromJSON(saved);See examples/session-persistence.js for a complete example.
Which Node.js version is required?
Node.js 18 or higher.
Contributing
Pull requests are welcome! Feel free to open issues for bugs or feature requests.
Roadmap
- [x] Session persistence
- [x] More examples
- [ ] Browser support
- [ ] SOCKS5 proxy support
License
MIT
