Automating Cookie Clicker with Python: Hooking into an Electron Game
Cookie Clicker is one of those games that starts as a joke and ends with you running a full-blown cookie empire. I wanted to see how far I could push automation — not by cheating with save editors or memory hacks, but by building a bot that plays the game the same way a human does: reading the screen and clicking. Here’s how Auto Clicker for Cookie Clicker works under the hood.
The Core Architecture
The bot uses a two-part architecture: an in-game JavaScript mod that reports UI element positions, and a Python automation layer that reads those positions and injects input.
┌─────────────────────────────────┐ ┌──────────────────────────────┐
│ Cookie Clicker (Electron) │ │ Python Bot (main.py) │
│ ┌───────────────────────────┐ │ │ │
│ │ shimmerBridge mod (.js) │──┼────→│ DOM loop (80ms poll) │
│ │ writes JSON coordinates │ │ │ ↓ │
│ │ to local file │ │ │ Priority decision engine │
│ └───────────────────────────┘ │ │ ↓ │
└─────────────────────────────────┘ │ pyautogui input injection │
│ win32gui window management │
│ ↓ │
│ PySide6 Qt HUD │
└──────────────────────────────┘
How the JavaScript Mod Works
The Steam version of Cookie Clicker runs on Electron, which means the game’s UI is all web-based. Since it has a mod system that loads JavaScript from the mods/local/ directory, we can inject our own code directly into the game process.
The mod — called shimmerBridge — does exactly one thing: it reads the positions of every important UI element and writes them to a JSON file on disk. This includes:
- The big cookie’s bounding box
- All visible golden/wrath cookie (shimmer) positions
- Spell button positions in the grimoire
- Garden plot coordinates
- Stock market ticker positions
Here’s the critical part of the coordinate reporting:
// Inside the Cookie Clicker mod context
function reportPositions() {
const elements = {
bigCookie: getRect(Game.bigCookie),
shimmers: Game.shimmers.map(s => ({
id: s.id,
type: s.type, // 'golden' or 'wrath'
x: s.l.x, y: s.l.y, w: s.w, h: s.h
})),
spells: Game.Objects['Wizard tower']?.minigame?.spellsById
?.map(s => ({ id: s.id, name: s.name, ready: s.ready })) || [],
gardenPlots: getGardenPlotPositions(),
stockGoods: getStockPositions(),
};
// Write to file for Python to read
Game.WriteSave('shimmerBridge', JSON.stringify(elements));
}
The mod runs inside the game’s own update loop, so positions are always fresh.
The Python Side: Reading Coordinates and Injecting Input
On the Python side, the bot polls that JSON file every 80 milliseconds. This is fast enough to catch golden cookies before they disappear, but slow enough to not hammer the filesystem.
The key challenge is mapping client-relative coordinates (what the mod reports) to absolute screen coordinates (what pyautogui needs). The bot uses win32gui to find the game window and calculates the offset:
import win32gui
import pyautogui
def client_to_screen(client_x, client_y):
"""Convert game-internal coordinates to absolute screen coordinates."""
hwnd = win32gui.FindWindow(None, "Cookie Clicker")
rect = win32gui.GetWindowRect(hwnd)
# Account for window borders and title bar
border_width = win32api.GetSystemMetrics(win32con.SM_CXSIZEFRAME)
title_height = win32api.GetSystemMetrics(win32con.SM_CYCAPTION)
border_adjusted = (
rect[0] + border_width,
rect[1] + title_height + border_width,
)
return (border_adjusted[0] + client_x, border_adjusted[1] + client_y)
The Priority-Based Decision Loop
The bot doesn’t just click randomly. It runs a strict priority loop that makes real-time decisions:
PRIORITY_ORDER = [
("shimmers", click_shimmers), # Golden/wrath cookies first
("spells", cast_spells), # Force the Hand of Fate
("stocks", trade_stocks), # Buy low, sell high
("garden", manage_garden), # Plant and harvest
("godzamok", execute_godzamok), # Sell-click combo
("buildings", buy_building), # ROI-based purchase
("upgrades", buy_upgrade), # CPS-boosting upgrades
("big_cookie", click_cookie), # Last: click the cookie
]
Each tick, the bot checks conditions in this order and executes the first actionable one. Golden cookies are always #1 because they’re time-sensitive — miss one and you lose a potential 777x clicking frenzy.
Stock Market: Hidden State Awareness
The stock market trader is one of the more interesting subsystems. Cookie Clicker’s stock market works on a hidden-state model — each stock has an internal mode (stable, slow_rise, fast_rise, slow_fall, fast_fall, chaotic) that isn’t visible to the player.
The bot tracks price history and uses threshold-based logic to infer the hidden mode:
def evaluate_stock(stock_id, price_history, mode):
prices = price_history[-10:] # Last 10 ticks
delta = prices[-1] - prices[0]
pct_change = delta / prices[0] if prices[0] else 0
if mode == "chaotic":
return "hold" # Too unpredictable
if pct_change < -0.15:
return "buy" # Deep dip
if pct_change > 0.25:
return "sell" # Strong gain
return "hold"
The Qt HUD and Controls
The bot ships with a PySide6 Qt dashboard that shows real-time stats and gives you control over every subsystem:
- Bot toggle — start/pause the automation loop
- Stock toggle — enable/disable stock trading
- Build toggle — enable/disable building autobuy
- Upgrade toggle — enable/disable upgrade autobuy
- Ascend toggle — enable/disable ascension prep
- Wrinkler cycle — switch between hold, seasonal farm, and shiny hunt modes
The theme system is centralized — all colors, fonts, and spacing are defined in a single qt_hud/styles/theme.py file, making it easy to customize the look.
Global hotkeys (Ctrl+Alt+F6 through F12) let you toggle features even when the game is focused, which is critical for real-time play.
OBS Overlay for Streamers
The bot includes a standalone OBS overlay server in the obs_overlay/ directory. It receives events from the bot via a local WebSocket connection and renders a transparent browser source showing:
- Current cookies per second
- Active buffs with countdown timers
- Bot status indicators
- Golden cookie streak counter
This is particularly useful if you’re streaming the game — your viewers can see exactly what the bot is doing.
Distribution with PyInstaller + Inno Setup
The bot is distributed as a proper Windows installer. The build pipeline uses PyInstaller to freeze the Python code into a standalone executable, then Inno Setup wraps it into a CookieClickerAutoClicker_Setup.exe with:
- Start Menu shortcuts
- Desktop icon
- Automatic mod syncing on first launch
- No Python installation required for end users
The entire CI/CD is handled by GitHub Actions — pushing a version tag (v*) triggers the full build and creates a release automatically.
Achievement Safety
One thing I want to emphasize: this bot is achievement-safe. It does not modify save files or hook into game memory. Every action is a simulated mouse click, which is indistinguishable from human input to the game. Cookie Clicker’s developer has stated that auto-clickers are an accepted part of the game’s culture, and the bot won’t trigger any achievement-disabling mechanisms.
Check out the full source and download the installer on GitHub.