Skip to content
[OPEN_POKER]♠

Zero to Open Poker Leaderboard in 7 Days: A Daily Plan

JJoão Carvalho||Updated |13 min read

You can take a poker bot from "doesn't exist" to a bot with a measurable baseline in 7 days. Whether it becomes competitive or ranks well depends on the player pool, variance, uptime, and the quality of your decisions. The platform lets a developer register, connect, and play on day 1, then add one strategy upgrade per day. Here's a practical plan with observable milestones.

Why does the 7-day plan work?

Because each day adds a single, isolated improvement on top of a working bot. You're not building a system end-to-end before the first hand. You're shipping a calling station on day 1 and improving it incrementally. By day 7, you can evaluate each change against recorded hands from real opponents; a short run still cannot prove that a strategy is profitable.

This is the opposite of how most bot projects fail. Most developers spend two weeks designing a "complete" architecture, then realize on day 14 that their hand evaluator doesn't match the protocol's card format, or their action sender forgets the turn token, or their pot odds calculator uses the wrong field. The 7-day plan defers all of that until the bot is already running.

More hands make your measurements less noisy, and uptime gives a bot more chances to demonstrate an edge. They do not guarantee a leaderboard increase: rankings depend on the season, opponents, bankroll rules, and other bots' uptime.

Day 1: Get a calling station running

Your only goal on day 1 is a connected bot that plays legal hands. Don't worry about strategy. Don't worry about profits. Don't worry about anything except: bot connects, bot joins table, bot responds to your_turn with a valid action, bot doesn't crash for 30 minutes.

Use the build a poker bot in Python guide as your starting point. Download the checkpoint, set OPEN_POKER_API_KEY in your local environment, and run it. A completed hand depends on other bots being available; the offline checkpoint lets you check the client while waiting.

The calling station strategy checks if possible, otherwise calls or folds. It gives you a connectivity baseline. Record how many hands actually complete and any errors; do not infer strategy strength from the first session.

End-of-day target: bot has played at least 20 hands, no crashes, no timeouts.

Day 2: Add pre-flop hand selection

The single biggest improvement you can make on top of the calling station. Most starting hands in Hold'em are losers; folding the bottom 60% pre-flop dramatically reduces the chips you bleed on the flop and beyond.

def should_play_preflop(cards):
    """Top ~40% of starting hands."""
    ranks = "23456789TJQKA"
    r1 = ranks.index(cards[0][0])
    r2 = ranks.index(cards[1][0])
    high, low = max(r1, r2), min(r1, r2)
    pair = r1 == r2
    suited = cards[0][1] == cards[1][1]
 
    if pair: return True
    if high >= 10: return True
    if high >= 8 and suited: return True
    if high == 12 and low >= 7: return True
    return False

Store the hole cards when hole_cards arrives. On your_turn, if it's preflop and should_play_preflop() returns False, fold. Otherwise fall back to the calling station logic.

This change should alter your action mix and usually reduces unnecessary post-flop exposure, but its profitability depends on the opponents and sample. Compare the logged results with day 1; do not use a short run to predict rebuys or rank.

Day 3: Add pre-flop raising

The day 2 bot folds the bad hands but never raises the good ones. Opponents see free flops against your premium holdings, which means they get to make hands that beat you. Fix: raise your top 15% of hands instead of just calling.

def should_raise_preflop(cards):
    ranks = "23456789TJQKA"
    r1, r2 = ranks.index(cards[0][0]), ranks.index(cards[1][0])
    pair = r1 == r2
    high, low = max(r1, r2), min(r1, r2)
    suited = cards[0][1] == cards[1][1]
    # Premium pairs
    if pair and r1 >= 7: return True  # 99+
    # Big aces
    if high == 12 and low >= 8: return True  # AT+
    # Suited broadway
    if suited and high >= 10 and low >= 9: return True
    return False

When this returns True and raise is in valid_actions, send a min-raise instead of just calling. The amount field is the raise-to total, not an increment. Use the min value from the raise action entry as your amount.

End-of-day target: compare the new action mix and chip result with day 2 over a similarly sized sample. Do not treat a break-even result as proof of a stable edge.

Day 4: Add pot odds for postflop calls

Postflop is where bots leak the most chips. Calling random bets without doing the math is what makes a calling station a calling station. Fix it with pot odds.

The math: divide the call amount by the pot after your call. If your estimated win probability exceeds that ratio, call. Otherwise fold. The poker math for bots tutorial covers the formula in detail.

def call_is_profitable(your_turn_msg, win_pct=0.30):
    actions = {a["action"]: a for a in your_turn_msg["valid_actions"]}
    if "call" not in actions:
        return False
    pot = your_turn_msg["pot"]
    call_amt = actions["call"]["amount"]
    if call_amt == 0:
        return True
    pot_odds = call_amt / (pot + call_amt)
    return win_pct > pot_odds

For this arithmetic exercise, 30% is an illustrative input, not a measured equity estimate. It cannot distinguish a missed draw from a strong made hand. Replace it with evaluated card samples in the equity lessons before relying on it for strategy.

End-of-day target: pot-odds decisions are logged with pot, call amount, estimate, and selected action so you can audit the rule on actual hands.

Day 5: Track opponent VPIP

Day 5 is when you stop playing every hand the same and start adapting to the table. Build a simple opponent tracker that logs how often each player puts chips in pre-flop. The opponent modeling guide has the full implementation, but a minimum viable version:

from collections import defaultdict
 
vpip_data = defaultdict(lambda: {"hands": 0, "voluntary": 0})
seen_this_hand = set()
voluntary_this_hand = set()
 
def on_hand_start():
    seen_this_hand.clear()
    voluntary_this_hand.clear()
 
def on_player_action(msg):
    name = msg.get("name", f"seat{msg['seat']}")
    action = msg["action"]
    # Count every observed player once in the denominator. Forced blind posts
    # are observed hands, but do not count as voluntary pre-flop action.
    if name not in seen_this_hand:
        vpip_data[name]["hands"] += 1
        seen_this_hand.add(name)
    if action in ("call", "raise", "all_in") and name not in voluntary_this_hand:
        vpip_data[name]["voluntary"] += 1
        voluntary_this_hand.add(name)
 
def get_vpip(name, default=0.25):
    data = vpip_data[name]
    if data["hands"] < 20:
        return default
    return data["voluntary"] / data["hands"]

Use VPIP to adjust your raising range. Against an opponent with VPIP under 15% in late position, expand your stealing range. Against an opponent with VPIP over 50%, only value-bet (don't bluff: they call too much).

End-of-day target: 800+ hands, bot is identifying at least 5 distinct opponents.

Day 6: Add bet sizing variation

Static bet sizing is the next leak. Most beginner bots either always min-raise or always pot-bet. Both are wrong. Mix three sizes based on the situation:

SpotSizeReasoning
Pre-flop open from late position2.5x BBStandard open, balances steal frequency with value
Continuation bet on dry board33% potCheap, gets weak hands to fold
Value bet on wet board75% potCharges draws, builds the pot for value

Compute your raise amount based on the spot, clamp to the min/max from valid_actions, and send. Mixing sizes makes you noticeably less exploitable. Opponents who track patterns can no longer guess your hand strength from your bet size alone. The betting strategy tutorial has the full breakdown.

End-of-day target: size choices are logged and clamped to the protocol's allowed range. Compare the distribution of sizes and results with the prior day; do not infer exploitability from one session.

Day 7: Run uptime, monitor, iterate

Day 7 isn't about new features. It's about running your bot for 12+ hours straight, watching the leaderboard, and patching whatever breaks. The debug guide covers the most common failure modes (auth issues, timeouts, race conditions).

Three things to check:

1. Crash log. Wrap your main loop in a try/except that logs every exception with a timestamp. Run for 4 hours, then read the log. Fix the most frequent error first.

2. Slow decisions. Add latency logging from the timeout guide. Anything over 1 second deserves investigation.

3. Win rate by hour. Group your hand history by hour of the day and check if your win rate varies. Some bots win during peak hours (more opponents = more weak players to exploit) but lose at off-peak times. Use this to decide when to keep your bot running.

End-of-day target: the bot has a recorded hand count, error-free run window, decision latency summary, and a reproducible deployment. Check the current leaderboard as a status signal, but do not use a percentile as a promised outcome.

What does the 7-day progression actually look like?

Use a table like this as a measurement template, not as an expected trajectory. Replace the values with your own logs; no fixed bb/100 or hand count is guaranteed by a particular day.

DayStrategy addedWhat to measureHands by EOD
1Calling stationrecord baselinerecord your total
2Pre-flop fold rangecompare with day 1record your total
3Pre-flop raise rangecompare with day 2record your total
4Pot odds postflopaudit decisionsrecord your total
5VPIP-based opponent readscompare by opponentrecord your total
6Bet sizing variationcompare by spotrecord your total
7Stability and uptimeverify the run windowrecord your total

The biggest jumps are days 2 and 5: pre-flop hand selection and opponent modeling. These are the cheapest improvements per line of code. Days 4 and 6 are smaller gains but they compound nicely. Day 7 doesn't add edge, but it converts the edge you already have into a leaderboard position by accumulating hands.

This is an experiment plan, not a study. Variance at 6-max is high, and individual results vary by the season's player pool. Keep changes whose results hold up against comparable samples.

What should you NOT do in the first week?

Three traps to avoid.

Don't write a hand evaluator from scratch. It's tempting because it feels like the "real" poker work. It's a multi-day project that adds no measurable edge over a simple win-probability heuristic. If you absolutely need hand strength, use PokerKit or Treys (Python libraries with battle-tested evaluators) instead of writing your own. We use PokerKit on the server side for the same reason.

Don't try to implement CFR or GTO solving. Counterfactual Regret Minimization is the technique behind Pluribus and Libratus. It's also a multi-month research project that requires tens of millions of training hands. For a first bot, you'll get better results by spending the same time on basic heuristics. Add CFR later if you want to push past the top 20%.

Don't deploy on day 1 with no error handling. Wrap your event loop in a try/except, log every exception, and keep going. Bots that crash on a single bad message lose all the table time they would have accumulated overnight. The fix is one try/except block.

What comes after day 7?

Once you have a working competitive bot, the next round of upgrades are incremental and high-impact:

  • Position-aware ranges: tighter under the gun, looser in the cutoff and button
  • Multi-street planning: think about what you'll do on the turn before you bet the flop
  • Bluff selection: pick boards where bluffs are credible (high cards, fewer draws)
  • Bankroll management: vary your buy-in based on session results

Each of these can help in the right pool, but the size of any gain must be measured from your own hand history. The path to a strong leaderboard finish is iterative: stack improvements, test them against comparable samples, and keep changes whose results hold up. The full platform docs cover every protocol detail you'll need for the next round.

FAQ

How long does it really take to build a competitive poker bot? Seven days of part-time work is a realistic schedule for a first bot with a few heuristic upgrades. A top-25%, top-10%, or top-1% result depends on the season and cannot be promised from a timetable; plan for continued iteration and tuning if you want to compete for those positions.

Can I follow this plan with a language other than Python? Yes. The protocol is pure WebSocket plus JSON, so any language with WebSocket support works. JavaScript, Go, Rust, Java, C++, even Bash with websocat have all been used to build bots on Open Poker. The Python examples translate directly.

How many hands do I need to play to climb the leaderboard? You need at least 10 hands to appear on the leaderboard at all. More hands reduce measurement noise, but there is no hand count that guarantees a rank; use the current leaderboard and your own results to decide whether a change is holding up.

Do I need a Pro account to run this plan? No. Everything in this plan works on a free account. The Pro tier ($5/season, with bundle discounts) adds analytics, custom strategies, and shorter rebuy cooldowns, but the strategy upgrades themselves are free. See the Pro feature comparison for the full list.

What if my bot busts out before I finish the plan? Auto-rebuy handles it. Send {"type": "set_auto_rebuy", "enabled": true} once after connecting and the server will automatically rebuy you (subject to a 5-minute cooldown on the free tier) when your bot busts. Your event loop keeps running and the next hand starts as soon as the cooldown expires.


Seven days of focused work is enough to take a poker bot from zero to a live, measurable baseline on Open Poker. The platform is designed for this iteration speed. Register a bot, follow the day-by-day plan, and use your logs and the current leaderboard to assess progress.

♠

Keep Reading