GGPoker Bot Developer FAQ
By Raul Moriarty ·Poker Software Expert
Twenty-one technical questions that come up regularly in the team chat — solvers, opponent models, latency budgets, detection topology, LLMs in poker, the open research frontier.
What this FAQ covers
- Solver theory and compilation: GTO baselines, action and state abstraction, multiway compression.
- Opponent modelling: convergence under anonymous tables, Bayesian priors, archetype bucketing.
- Engineering: latency budgets, multi-table state isolation, UI automation, mobile-vs-desktop tradeoffs.
- Detection: behavioural shaping, action-timing distributions, adversarial-classification frame.
- The open frontier: where the research is moving in 2026.
A GTO solver computes a strategy offline for a defined game tree (preflop ranges, a specific board, a specific bet-sizing menu) by iterating CFR or one of its variants — PioSolver, GTO+ for HU/6-max, MonkerSolver for multiway. The output is a giant lookup table of action frequencies. A real-time bot takes that table as a baseline, queries it under a millisecond-level latency budget against live game state, and overlays an online opponent model that pushes the action away from the GTO baseline when an exploitable tendency is detected. The solver is the textbook; the bot is the player.
Heads-up gives you a single opponent and dense information per hand — every action is against the same player, every showdown updates the same posterior. 6-max gives you five opponents, each updated only when they enter a hand, with rotation between hands. The model architecture changes accordingly: HU runs a fine-grained per-board-texture model on one opponent; 6-max runs a coarser cross-opponent model that buckets opponents into 3–5 archetypes (loose-passive, tight-aggressive, station, maniac, unknown) and refines the bucket assignment over the session.
Rake is the dominant cost at low stakes. GGPoker's rake on NL10 6-max runs around 6–8% with rakeback offsetting some of that, on NL50 around 4–5%, and on NL200 around 3% effective. Combined with falling win-rate-vs-population at higher stakes (regs are more solver-aware), the EV-per-hour curve peaks somewhere in the NL25–NL100 band depending on the format. Spin & Gold has different math because the rake structure is flatter and the variance is heavily front-loaded — the €5 and €10 buy-ins clear positive EV on volume but require thousands of games for sample.
By shape, not by mean or variance alone. Human action-timing distributions are log-normal-ish with state-dependent location and heavy right tails — snap-folds in 600-1200ms, hard rivers in 5–30 seconds, occasional 8–25 second "distraction" tails that are state-independent. A bot that adds uniform noise around a centroid has the wrong distributional shape. A bot that draws from a fixed log-normal also fails because the location parameter needs to condition on decision difficulty. The full discussion is in the detection note.
Two reasons. First, the game tree is wider — chess has roughly 35 legal moves on average per position; NLH preflop has continuous bet-sizing on top of fold/check/call/raise, which abstraction must discretise and lose information doing so. Second, the equilibrium is opponent-conditional in a way chess isn't. Chess equilibrium is well-defined regardless of opponent skill; poker GTO is an equilibrium against an opponent also playing GTO, and the highest-EV strategy against a non-GTO opponent is generally a deviation from GTO. "Solved" preflop charts exist for the GTO equilibrium; the highest-EV preflop play does not.
Approximately none for live decisions, useful for adjacent tasks. Frontier LLMs hallucinate ranges, misapply ICM, lack calibrated frequency intuition, and have no concept of position-conditional bet-sizing. They cannot beat a $5 buy-in heads-up bot built on solver output. They are useful for hand-history annotation, exploit-hypothesis generation, training-data synthesis, and natural-language summaries of solver outputs. The boundary between "useful annotation tool" and "useful in-the-loop player" is sharper than the field acknowledges.
The empirical floor is around 80-150 hands of joint observation for a useful exploitative deviation — enough to estimate VPIP and PFR to ±5pp with low-confidence overlays on c-bet response and 3-bet frequency. A population-conditioned Bayesian prior can cut this to 40-60 hands in principle; the open research question is whether the prior remains robust across the fish-vs-reg distribution at GGPoker, where the bimodality is sharper than at older European pools.
Each table runs its own state machine with its own decision queue. A naive implementation shares a CPU and clocks decisions sequentially, which creates observable cross-table action latency correlations — table A's hard river decision delays table B's snap-fold, and the correlation is detectable. The right architecture is preemptive: a tough decision on table A surrenders the CPU and rejoins the queue when easier decisions are pending, with each table's behavioural-timing distribution sampled independently. Production systems also add a per-table "alertness" parameter that drifts down over long sessions to mimic human fatigue.
On a modern Android device (Snapdragon 8 Gen 2 class), 30-80ms for solver-table lookup, 5-15ms for opponent-model update, 10-30ms for UI inspection on the rendered client. Total compute budget around 100-150ms per action. The human-perceptible action latency is the behaviourally-shaped sample on top of that, which is typically 600ms to several seconds. The compute budget is comfortable; the constraint is power consumption over long sessions.
Three streets of betting, a board that has revealed most of its information, and 2-4 opponents whose ranges have narrowed materially. The game tree under reasonable bet-sizing abstraction blows up faster than any other street. MonkerSolver's depth-limited subgame solving handles the math but only for specific tree shapes; producing a general-purpose multiway turn policy that compiles to a mobile inference budget is genuinely open. The current production approach is opportunistic — solved for high-frequency tree shapes, fall back to heuristic-plus-opponent-model for the rest.
Three-handed hyper turbos have completely different math from 6-max cash: 25bb starting stacks, super-fast blind levels, multiplier-aware ICM at the high end (a 1000x spin has different bubble dynamics than a flat 2x). Push-fold charts dominate from about 12bb down; the equilibrium changes shape entirely. Using a cash engine on a Spin table loses money fast because the cash engine over-deepens its lines into stack depths that do not exist.
Equity distributions flatten because each player has six two-card combinations rather than one — preflop equity differences between hands shrink, blockers matter more, and turn play has higher EV-per-decision than river play. The solver outputs are larger and harder to compress, opponent-modelling features differ (3-bet frequency by hand class is less informative; reraise frequency given board texture is more), and the UI automation layer needs to handle four hole cards instead of two. The same engineering scaffolding applies; the strategic content is genuinely different.
Two compression axes. First, state abstraction: bucket the game state into equivalence classes by board texture, stack-to-pot ratio, position, and action history, reducing the lookup key from raw state to a small index. Second, action abstraction: discretise the bet-sizing continuum into a fixed menu (e.g., 33%, 66%, 100%, 150%, all-in) and re-solve at the abstraction. The combined compression is typically 4-5 orders of magnitude versus the raw CFR output, with a measurable but bounded EV loss against the unabstracted strategy.
Android is the production target because the application sandbox is permissive enough to support accessibility-service-driven input automation with relatively stable behavioural shaping. iOS is significantly harder because the sandbox blocks the input-automation surface and the available alternatives (jailbreak, MDM exploitation) are unstable across OS versions. Most production poker AI runs Android-only as a result, which has the side effect of concentrating detection-side analysis on Android-typical telemetry — a small but useful population shift.
Hardware-level entropy is the hardest. Operators collect sensor data on mobile (accelerometer drift, gyroscope micro-movement during gameplay), CPU clock skew, and battery-discharge profiles. A device sitting on a desk running 12-hour sessions has a measurably different sensor profile from a device held by a human. Some implementations sit the device in a powered cradle and add programmatic micro-perturbations to the sensor feed, which works against the cheap variant of this check; it is unclear how it performs against more sophisticated operator-side analysis.
Not as an immediate ban-hammer. The visible sequence runs: quiet flag → soft restriction (withdrawal limits drop, KYC re-verification requested) → structured interview from support → confiscation and closure. The cycle takes 2 weeks to 9 months depending on review-queue capacity and triggering events; the most common accelerator is a large first withdrawal. The detection page covers the review pipeline in more depth.
Yes but they age fast. The classical benchmarks were the ACPC (Annual Computer Poker Competition) and its successor evaluations; Tartanian, Slumbot, and Pluribus all measured against pre-defined opponent pools. The current academic frontier sits in the Brown-Sandholm lineage at CMU and the DeepStack/DeepMind direction. Production poker AI has moved meaningfully ahead of public benchmarks in 2023-2026, partly because production systems are tuned against real opponent populations rather than research baselines.
Roughly: solver baseline gives you a near-zero-EV strategy against good opponents and a positive-EV strategy against the population. Opponent modelling adds 1-4 bb/100 against typical pools depending on how exploitable the opponents are. Detection-aware behavioural shaping costs back 0.5-1.5 bb/100 versus pure-GTO output. The net is typically 2-5 bb/100 at NL25-NL100 on GGPoker, scaled by hands-per-hour (60-80 per table, multi-tabled) and effective stake. Numbers are pool-dependent and degrade as the regs in your pool adopt better solver work themselves.
UI automation reliability. The interesting engineering is in solvers and opponent models; the breakage in production is almost always in the screen-scrape and action-emission layer. GGPoker ships client updates 4-6 times a year, of which 1-2 break something the input layer depends on. The shipping engineering effort over a year is dominated by keeping the boring layer working, not by improving the interesting math.
Three places. Online opponent-model convergence under anonymous identity rotation. Detection-aware policy combiners in the adversarial-classification frame. Compiling Pluribus-scale multiway outputs into mobile inference budgets without unacceptable EV loss. None of these are solved; all of them are active enough that a serious contributor can move the field. The team chat is one place that discussion happens.
Read the notes on this site, including the references at the bottom of the detection page, and the homepage's open questions. If you have data or implementation experience on any of the open threads, reach out through the chat link below. The chat is low-volume and read by the team; sales pings and "give me a copy of your bot" requests get auto-archived.
Question we didn't cover?
Ask the team in the chat. The FAQ is updated when a new question gets asked twice.