One decision saved us setup time on every store, kept catalogue pages fast and stopped more bots: a self-hosted, Turnstile-style challenge that installs itself.
Part 5 of 5 in the anti-bot series. New here? Start with Part 1, the overview: *Magento Anti-Bot and Anti-Scraping Guide.*
Cloudflare Turnstile is a lovely idea. Most visitors never see a puzzle. Their browser quietly proves itself in the background, and only the doubtful ones get asked anything. No traffic lights, no crosswalks, no squinting at a bicycle wondering whether the handlebar counts.
I wanted exactly that for every Magento store we run. Without the Cloudflare part, and, more importantly, without anyone having to set it up.
This post is about the one decision that ended up saving us time every day, making stores faster and making them safer, all at once. Three wins from one fairly boring decision. Those are my favourite kind.
The chore nobody puts on the roadmap
A captcha sounds like a five-minute job. For one store, it is.
Turnstile is set up per site, by a person: create the account, generate the keys, wire the widget into the store, register the domains. Then do it again for the next store. And the next one. And the staging copy of the next one.
That list hides the worst part: the sign-up. Before a single shopper sees a checkbox, Turnstile wants an account: register, confirm your email, add the domain, generate a site key and a secret key, install a Magento module to wire it all in, then discover the staging domain needs its own entry. All of that for a little box that says I am not a robot.
Then the back and forth starts. Emails to confirm, API keys to pass along, a module to install and keep updated. One person has the login, another has the store, and the keys live in an email thread nobody can find six months later. A domain changes and the whole dance starts again. Do that for a fleet of stores and you have a part-time job that nobody applied for.
Multiply that by every store you run and a captcha you set up by hand becomes a captcha someone, one day, forgets.
Shopping for an engine
So we went shopping. It turned out to be harder than building one, which we had already tried. Every option was good at something and wrong for us in a different way.
Google reCAPTCHA ships with Magento, so it was the obvious default. It also sends visitor data to Google, and on a bad day it asks your shoppers to find the bicycles.
Cloudflare Turnstile had exactly the right idea. But every store means the same round trip: an account, emails, API keys and a Magento module to install and keep updated, plus a vendor in the checkout path. Time and effort we did not want to spend, over and over.
Anubis is a whole proxy that puts every visitor through the puzzle. Brilliant for a code forge drowning in AI crawlers. Too blunt for a shop, where the visitor you challenge is often the one about to pay.
Cap came closest: open source, self-hosted, no image puzzles. It is deployed as a service of its own, though, which means one more thing to run and keep updated next to every store.
ALTCHA won on the boring things. It is open source, self-hosted and collects nothing, and it ships official libraries in both Go and PHP, the two languages our two layers already speak. So the same protocol runs twice on every store, by default: once at the edge, in front of everything, and once inside Magento, on the storefront forms.
Win one: time. It installs itself.
Both copies of ALTCHA are part of the store from the moment it is provisioned. The edge one ships inside our OpenResty container; the Magento one ships as a module in every shop's base package. No accounts, no keys, no widget to wire in, no checklist.
Every store runs the same protection, at the same version, from day one. Nobody has to go through a captcha integration, and nobody can forget to.
That is the daily saving. Not one big afternoon, but a long tail of small chores that simply never appear on anyone's list again.
Win two: speed. Bots pay before PHP does.
Here is the part people do not expect: the security layer made stores faster.
A cached product page is almost free. Catalogue search, or a category filtered by five attributes at once, is real database work. Bots love those pages the way toddlers love lift buttons: every combination, again, forever.
So a visitor who lands on catalogue search cold, with no history on the store, solves a small puzzle first. A shopper never notices; their browser does it while they read. The first burst this met came from 1,477 addresses. None of it reached PHP, and the server's load dropped from about 12.6 to 3.2.
On deep layered-navigation filters the price is dynamic: when a store is being hammered, the puzzle gets harder for everyone who has not earned trust yet. The share of abusive filter requests reaching PHP went from nearly all of them to 0.025%, with no real shoppers caught.
Every request the edge turns away is a PHP worker your shoppers get to keep.
Win three: security. Bots pay a toll.
If you read ZDNet's piece on Anubis, the open-source blocker that makes every visitor solve a proof-of-work puzzle, you will recognise the idea. Anubis is great, and honest about its limits: its own README calls it a bit of a nuclear response. In August 2025, Codeberg reported that AI crawlers had learned to solve its challenges.
We saw the same. One swarm solved our challenge 2,490 times out of 2,490. Politely. Instantly.
That is not a failure of proof of work, it is a misunderstanding of it. Proof of work is not a wall. It is a toll. A shopper pays it once, in a moment of CPU they never notice. A scraper pays it on every fresh session, forever, at whatever price the store is currently charging. And while it pays, every other layer is still watching: the fingerprints, the scoring, the crawler checks, the firewall.
Across multiple production stores over a given period, 404,149 visitors were shown the full challenge page, and 85.6% of them never solved it. The click-to-verify version, reserved for the highest scores, was solved by 3.1%. Which tells you who was getting it.
When we ask, and when we don't
The Anubis approach puts every visitor through the puzzle. For a shop, that is a conversion tax on the people you most want to keep. Nobody in history has ever checked out faster because of a captcha. So we only ask when:
It is a browser's first visit, invisibly, on the real page.
The score is doubtful, also invisibly.
The score is high, with a short interstitial that solves itself.
A cold visitor asks for an expensive page, before the query runs.
The store is under pressure, at a higher price for everyone not yet trusted.
Verified search engines never see it. Returning shoppers with a valid pass do not see it again for a while. And inside Magento, ALTCHA also replaces reCAPTCHA on the storefront forms, so they get the same treatment without a single traffic light.
How we got here, in three versions
Before any of this, the defence was rate limits and block lists. It had exactly two words in its vocabulary, yes and no, and was very confident about both. What was missing was a third answer: maybe. Prove it.
**Version one **was homegrown. Launch day took about twenty-five commits, most of them us changing our minds about who deserved a puzzle. I am not proud of that number.
**Version two **swapped our own cryptography for ALTCHA, because writing your own crypto is the kind of hobby that ends in a blog post titled lessons learned. Along the way we tried a classic squiggly-letters captcha and dropped it quickly: modern text recognition reads squiggly letters better than people do, so it was a test only humans could fail.
**Version three **settled on one rule: solving the puzzle is the browser test. Everything else only decides how hard we ask, never whether a real browser gets the chance to answer.
Was it worth not using Turnstile?
Honest answer: yep, 100%. Turnstile has something we never will: signal from a huge slice of the internet. If you are on Cloudflare already, use it and go outside.
We are not. For us, owning it means no third-party script on any page, no vendor in the checkout, no visitor data leaving the store, and a challenge we can tune per store when an attack changes shape. The price was three versions, a couple of embarrassing bugs.
I would do it again. I would just do it in one version instead of three.
Numbers in this post come from the edge logs of selected production stores we operate, over a given period — about 8.5 million requests. Store names are left out on purpose.
The anti-bot series: *Part 1: Overview · Part 2: OpenResty vs NGINX, Caddy and Traefik · Part 3: How to Spot a Fake Chrome · Part 4: How to Build a Bot Score · Part 5: Self-Hosted Proof of Work with ALTCHA.*
StoreFrame runs a self-hosted, Turnstile-style proof-of-work challenge at the OpenResty edge of every Magento store, priced by what each request costs, with no third party in the path.

Top comments (0)