Skip to content
Devansh Soni
All posts

I Got Tired of Clicking Cookie Clicker, So I Wrote JavaScript Instead

It started with something incredibly stupid.

  • javascript
  • automation
  • games

It started with something incredibly stupid.

I was playing Cookie Clicker.

If you haven't played it, the premise is exactly what the name suggests: you click a giant cookie, get cookies, buy buildings, get more cookies, and then use those cookies to buy things that make even more cookies.

At some point, the game introduces Golden Cookies. They randomly appear on the screen and give you powerful temporary boosts. One of them, Click Frenzy, gives a ridiculous boost to your clicking power for a few seconds.

There was just one problem.

I wasn't always around to click the Golden Cookie.

And apparently, my solution to this very serious problem was to write JavaScript.


The first step: catch the Golden Cookie

My first thought was to use a normal auto-clicker. But that felt unnecessarily crude.

Cookie Clicker runs in the browser, which means the game itself is written in JavaScript. So instead of looking at the screen and trying to figure out where a Golden Cookie appeared, why not ask the game directly?

That turned out to be much easier.

Cookie Clicker keeps track of its active Golden Cookies internally through an array called Game.shimmers. So I could periodically check that array and look for anything whose type was "golden".

The first version was ridiculously small:

window.goldenBot = setInterval(() => {
    Game.shimmers.forEach(shimmer => {
        if (shimmer.type === "golden") {
            shimmer.pop();
        }
    });
}, 100);

Every 100 milliseconds, the script checks for Golden Cookies.

If one exists, it pops it.

That's it.

I waited for the next Golden Cookie to appear.

It disappeared by itself.

It worked.

That was probably the moment when this stopped being a game and became a programming experiment.

There was one small problem: it eventually clicked Wrath Cookies too. Internally, both use the broad shimmer type "golden"; the wrath flag distinguishes them. So we corrected the detector:

window.goldenBot = setInterval(() => {
    Game.shimmers.forEach(shimmer => {
        if (shimmer.type === "golden" && shimmer.wrath === 0) shimmer.pop();
    });
}, 100);

That tiny bug was a useful lesson: the state behind the screen matters more than what an object looks like.

Diagram 1 — How the first bot worked

Golden Cookie spawns → Game.shimmers detects it → shimmer.pop() → reward activated


Then I discovered Click Frenzy

Catching Golden Cookies was useful, but it wasn't the interesting part.

One of the Golden Cookie effects is Click Frenzy. It gives an enormous temporary multiplier to clicking power.

So I thought:

If JavaScript can detect the Golden Cookie, can it also detect the buff?

Yes.

Cookie Clicker exposes its active buffs too, which meant I could check whether Click frenzy was currently active.

That gave me the next upgrade:

if (Game.hasBuff("Click frenzy")) {
    Game.ClickCookie();
}

Now the script wasn't just catching Golden Cookies.

It could also tell when Click Frenzy was active and start clicking the giant cookie automatically.

So the whole process became:

Golden Cookie appears → automatically click it → Click Frenzy activates → automatically click the big cookie → buff expires → stop clicking.

This was much more satisfying than a generic auto-clicker because the script actually understood what was happening inside the game.

It wasn't blindly clicking a location on the screen.

It was interacting with the game's own state.

Diagram 2 — The Click Frenzy automation

              Golden Cookie


             Detect shimmer


              Pop the cookie


          ┌──────────────────┐
          │ Click Frenzy?    │
          └────────┬─────────┘
                   │ YES

          Click the Big Cookie


             Buff expires


              Stop clicking

Then we stopped waiting for Click Frenzy altogether

At this point I had a thought that was probably not going to make the Cookie Clicker developers proud.

If the game lets JavaScript detect Click Frenzy, maybe JavaScript can also trigger Click Frenzy.

It could.

The game exposes a function for adding buffs, so we could repeatedly check whether Click Frenzy was active and activate it whenever it wasn't.

That gave us this:

window.frenzyBot = setInterval(() => {
    // Activate Click Frenzy if it isn't already active
    if (!Game.hasBuff("Click frenzy")) {
        Game.gainBuff("click frenzy", 13, 777);
    }
 
    // Click the big cookie while Click Frenzy is active
    if (Game.hasBuff("Click frenzy")) {
        Game.ClickCookie();
    }
}, 10);

And suddenly the game had become:

Click Frenzy → click like crazy → Click Frenzy expires → immediately activate another one → repeat.

No more waiting for a Golden Cookie.

No more waiting for the buff.

Just an almost permanent state of:

🍪 CLICK CLICK CLICK CLICK CLICK

To stop it:

clearInterval(window.frenzyBot);

We also used a forced Golden Cookie to test the automation without waiting for a real one:

var testCookie = new Game.shimmer("golden");
testCookie.force = "click frenzy";

That was particularly fun because it meant I could essentially spawn the exact Golden Cookie effect I wanted and watch the automation react to it.

At this point, Cookie Clicker wasn't really being played anymore.

It was being programmed.


The Sugar Lump rabbit hole

Cookie Clicker also has Sugar Lumps.

Normally, they take hours to mature.

And, honestly, waiting several hours for a tiny piece of digital candy didn't sound particularly exciting anymore.

So I inspected the game's internal state again.

One of the values Cookie Clicker keeps track of is Game.lumpT, which represents the timestamp associated with the current lump's growth.

The game also exposes the amount of time required for the lump to become ripe.

That meant we could essentially tell the game:

"Yeah, this lump has definitely been growing long enough."

After a bit of experimenting, we found a simple approach:

Game.lumpT = Date.now() - Game.lumpRipeAge;
Game.doLumps();

That makes the game treat the current lump as having reached its ripe time.

Then we could harvest it.

Because harvesting starts another lump growing, the same idea could be repeated automatically.

The final little lump bot looked like this:

window.lumpBot = setInterval(() => {
    // Make the current lump ripe
    Game.lumpT = Date.now() - Game.lumpRipeAge;
 
    // Update the game's lump state/display
    Game.doLumps();
 
    // Harvest it
    Game.clickLump();
}, 100);

Suddenly, instead of:

Wait 7–8 hours → harvest one lump

we had:

New lump → instantly ripe → harvest → new lump → repeat.

Diagram 3 — From manual gameplay to automation

                    COOKIE CLICKER

            ┌─────────────┼─────────────┐
            ▼             ▼             ▼
      Golden Cookies  Click Frenzy   Sugar Lumps
            │             │             │
            ▼             ▼             ▼
       Auto-detect     Auto-click     Auto-ripe
            │             │             │
            └─────────────┼─────────────┘

                  JavaScript Automation


                   🍪 Infinite chaos

Then the Grandmapocalypse showed up

Next came the insect-looking Wrinklers around the big cookie. They were exposed through Game.wrinklers, so we could pop the current swarm with:

Game.wrinklers.forEach(w => w.hp = 0);

But Wrinklers are strategically useful, which introduced a better idea: a good bot shouldn't simply click everything — it should decide when an action is worthwhile.

Christmas also gave us Reindeer, another shimmer we could detect:

window.reindeerBot = setInterval(() => {
    Game.shimmers.forEach(shimmer => {
        if (shimmer.type === "reindeer") shimmer.pop();
    });
}, 100);

The pattern was becoming clear: inspect state → identify mechanic → decide → automate.


The funny part: Cookie Clicker already has a JavaScript Console

At some point, I noticed a building in the game called JavaScript Console.

For a second I thought I had somehow discovered an actual in-game developer console.

Nope.

It's just a building.

But honestly, it might be one of Cookie Clicker's best jokes.

By that point I was already sitting in the browser's real JavaScript console, writing scripts to manipulate the game, while Cookie Clicker was casually selling me a building called JavaScript Console.

It almost felt like the game was acknowledging what I was doing.

"Yeah, you've played long enough. You probably know JavaScript now."


What actually made this fun

The interesting part wasn't really the cheating.

It was discovering how much of the game was accessible directly through JavaScript.

A traditional screen-based bot would have needed to look at pixels, locate a Golden Cookie, move the mouse there, and click it.

Our approach was completely different.

We were talking directly to the game's state.

Instead of saying:

"There is something yellow somewhere around these coordinates."

we could say:

"Does Game.shimmers contain a Golden Cookie?"

Instead of:

"The screen looks like Click Frenzy is active."

we could ask:

"Does Game.hasBuff("Click frenzy") return true?"

And instead of waiting hours for a Sugar Lump, we could inspect its internal timer and tell the game it had reached its ripe point.

That distinction is what made the whole experiment surprisingly fun.


From playing a game to programming one

Cookie Clicker is obviously not designed to be played this way.

And that's kind of the point.

Once you realize that the game is essentially a large JavaScript program running in your browser, the boundary between playing the game and programming the game becomes very thin.

We started with one tiny automation:

"Don't let me miss Golden Cookies."

Then:

"Automatically exploit Click Frenzy."

Then:

"Why wait for Click Frenzy at all?"

Then:

"Why wait several hours for Sugar Lumps?"

And suddenly the browser console had become a little control panel for the game.

What started as a tiny quality-of-life script turned into a miniature exercise in inspecting game state, understanding JavaScript objects, experimenting with internal functions, and automating decisions.

I couldn't tell whether I was playing Cookie Clicker anymore.

Or whether Cookie Clicker had quietly become my JavaScript playground.

Either way...

the cookies are going up. 🍪


Future scope: automate the entire game

Eventually the obvious question became:

Why stop here?

These DevTools snippets could become a proper mini-project: a modular Cookie Clicker automation engine that plays and optimizes most of the game on its own.

We already have Golden Cookie detection, Wrath filtering, Click Frenzy automation, continuous Click Frenzy experimentation, Sugar Lump automation, Wrinkler handling and Reindeer detection.

The next step is to separate the project into three layers:

                    COOKIE BOT

          ┌─────────────┼─────────────┐
          ▼             ▼             ▼
       Sensors       Strategy       Actions
          │             │             │
   Read game state   Decide what   Click / buy /
   buffs, timers,    is optimal    harvest / cast
   prices, etc.          │             │
          └─────────────┼─────────────┘

                  Cookie Clicker

From there, it could automate optimal building/upgrades, buff combos, Wrinklers, seasons, Garden mutations and harvesting, Grimoire spells, Pantheon strategies, Stock Market trading, dragon auras, Sugar Lump spending, achievements and even ascension decisions.

The problem then changes from "How do I automatically click this?" to:

"Given the entire game state, what is the best action the bot can take next?"

There is already prior art: other open-source Cookie Clicker projects automate combinations of purchasing, Golden Cookies, Wrinklers, Garden management, Grimoire, seasonal mechanics and other systems. So the interesting part of our project would be designing our own architecture and strategy engine from the mechanics we've been discovering ourselves.

That turns a joke about missing Golden Cookies into a legitimate mini-project involving state management, event-driven automation, heuristics and optimization.

So the natural next chapter is a GitHub repository.

From goldenBot to an autonomous Cookie Clicker player. 🍪🤖