npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.

Readme

akinator-client

npm version npm downloads license typescript

A modern, fully typed Node.js client for the Akinator game.

Contents

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-client

Create 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 /exclude endpoint (used by continue()) 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 make continue() 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 fresh start() 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