{"id":382952,"date":"2026-10-12T10:51:48","date_gmt":"2026-10-12T10:51:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/bot-storm-radar\/"},"modified":"2026-10-12T10:51:38","modified_gmt":"2026-10-12T10:51:38","slug":"bot-storm-radar","status":"publish","type":"plugin","link":"https:\/\/gu.wordpress.org\/plugins\/bot-storm-radar\/","author":4487455,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.5.0","stable_tag":"0.5.0","tested":"7.1.3","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"Bot Storm Radar","header_author":"ProWoos","header_description":"Bot attacks no longer come from one address. They come as swarms of thousands of addresses that each make one request, and a tool that judges visitors one by one sees nothing wrong. Bot Storm Radar watches the crowd instead. Every minute it counts how many addresses visited, how many made a single request, how many loaded assets like a real browser and how the browser names are spread, turns that into a storm score, learns the site's normal traffic and tells you in plain words when a bot storm is running. It also refuses requests for files only scanners ask for before a page is built, and, once you switch address bans on, bans for a while the single addresses that keep probing or asking for missing pages.","assets_banners_color":"1d2327","last_updated":"2026-10-12 10:51:38","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/ProWoos-Devs\/bot-storm-radar","header_author_uri":"https:\/\/github.com\/ProWoos-Devs","rating":0,"author_block_rating":0,"active_installs":0,"downloads":34,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.5.0":{"tag":"0.5.0","author":"rafael.minuesa","date":"2026-10-12 10:51:38","revision":3741153}},"upgrade_notice":{"0.5.0":"<p>The DNS check of search bots is now off unless you switch on Search bot check on the Settings tab.<\/p>","0.4.0":"<p>The address lists are no longer downloaded unless you switch on Address lists on the Settings tab.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3741154,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3741154,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3741154,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3741154,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3741154,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.5.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3741154,"resolution":"1","location":"assets","locale":"","width":1280,"height":777},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3741154,"resolution":"2","location":"assets","locale":"","width":1112,"height":938},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3741154,"resolution":"3","location":"assets","locale":"","width":1112,"height":698},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3741154,"resolution":"4","location":"assets","locale":"","width":1280,"height":1254},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3741154,"resolution":"5","location":"assets","locale":"","width":1112,"height":1368},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3741154,"resolution":"6","location":"assets","locale":"","width":526,"height":198}},"screenshots":{"1":"The Radar tab during a storm, with the current state, the score of the last minute, the learned baseline and the last 24 hours.","2":"The storm timeline. Every transition is listed with the numbers that caused it, in words.","3":"Request classes, the busiest networks and user agents, and search-bot claims with their verification.","4":"The Bans tab, with each ban's evidence and an Unban button, the bans that would have happened in observe mode, and claims waiting for a search-bot check.","5":"The settings for address bans and probe refusal.","6":"The dashboard widget."}},"plugin_section":[262246],"plugin_tags":[166108,4866,1174,5603,600],"plugin_category":[54],"plugin_contributors":[251386],"plugin_business_model":[],"class_list":["post-382952","plugin","type-plugin","status-publish","hentry","plugin_section-dashboard-widgets","plugin_tags-bot-protection","plugin_tags-bots","plugin_tags-firewall","plugin_tags-monitoring","plugin_tags-security","plugin_category-security-and-spam-protection","plugin_contributors-rafaelminuesa","plugin_committers-rafaelminuesa"],"banners":{"banner":"https:\/\/ps.w.org\/bot-storm-radar\/assets\/banner-772x250.png?rev=3741154","banner_2x":"https:\/\/ps.w.org\/bot-storm-radar\/assets\/banner-1544x500.png?rev=3741154","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/bot-storm-radar\/assets\/icon.svg?rev=3741154","icon":"https:\/\/ps.w.org\/bot-storm-radar\/assets\/icon.svg?rev=3741154","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/bot-storm-radar\/assets\/screenshot-1.png?rev=3741154","caption":"The Radar tab during a storm, with the current state, the score of the last minute, the learned baseline and the last 24 hours."},{"src":"https:\/\/ps.w.org\/bot-storm-radar\/assets\/screenshot-2.png?rev=3741154","caption":"The storm timeline. Every transition is listed with the numbers that caused it, in words."},{"src":"https:\/\/ps.w.org\/bot-storm-radar\/assets\/screenshot-3.png?rev=3741154","caption":"Request classes, the busiest networks and user agents, and search-bot claims with their verification."},{"src":"https:\/\/ps.w.org\/bot-storm-radar\/assets\/screenshot-4.png?rev=3741154","caption":"The Bans tab, with each ban's evidence and an Unban button, the bans that would have happened in observe mode, and claims waiting for a search-bot check."},{"src":"https:\/\/ps.w.org\/bot-storm-radar\/assets\/screenshot-5.png?rev=3741154","caption":"The settings for address bans and probe refusal."},{"src":"https:\/\/ps.w.org\/bot-storm-radar\/assets\/screenshot-6.png?rev=3741154","caption":"The dashboard widget."}],"raw_content":"<!--section=description-->\n<p>Bot attacks no longer come from one address. They come as swarms of thousands of addresses that each make one or two requests, so a tool that judges visitors one by one sees nothing wrong. Bot Storm Radar watches the crowd instead.<\/p>\n\n<p>Every minute it counts how many different addresses visited, how many made only one request, how many loaded a stylesheet or a script the way a real browser does, and how evenly the browser names are spread. It turns that into a storm score, learns what normal traffic looks like on your site, and tells you in plain words whether a bot storm is running right now and why.<\/p>\n\n<p>It also protects. It refuses requests for files only scanners ask for before WordPress builds a page, and a single address that keeps probing or asking for missing pages can be banned for a while. Address bans start in observe mode, where they are listed and nobody is refused, until you switch them on.<\/p>\n\n<p><strong>The radar<\/strong><\/p>\n\n<ul>\n<li><strong>Swarm metrics every minute.<\/strong> Single-hit ratio, asset ratio, user-agent evenness, error pressure and endpoint concentration, combined into one storm score and gated by traffic volume.<\/li>\n<li><strong>Learned baseline.<\/strong> Over the first seven days the plugin learns the site's normal number of distinct addresses per minute and its normal asset ratio, and shows them beside each threshold.<\/li>\n<li><strong>Storm states.<\/strong> Calm, warning, storm and cooling. Every transition is logged with the numbers that caused it and an explanation in words.<\/li>\n<li><strong>Alerts<\/strong> by plain-text email on warning, storm and all-clear.<\/li>\n<li><strong>Good-bot verification.<\/strong> DuckDuckBot is verified against its published address list. Googlebot, Bingbot, Applebot and Yandex are verified by reverse DNS plus forward confirmation once you switch on the Search bot check; until then their claims are counted as not checked and never banned. A user agent alone proves nothing.<\/li>\n<li><strong>The real visitor address behind a proxy.<\/strong> A forwarding header is believed only when the request arrived through Cloudflare, a local proxy or a proxy you declare. A spoofed <code>X-Forwarded-For<\/code> from an ordinary client is ignored.<\/li>\n<li><strong>Radar screen<\/strong> with the current state, the last 24 hours per minute, top classes, top keys, bot claims and the storm timeline, plus a dashboard widget.<\/li>\n<\/ul>\n\n<p>The radar observes and reports. It never blocks a swarm. On a quiet site the numbers stay near zero and the state stays calm.<\/p>\n\n<p><strong>The protection<\/strong><\/p>\n\n<ul>\n<li><strong>Refused early.<\/strong> The refusal runs as soon as WordPress has loaded its plugins, before the theme, the query or any page is built, and reads its rules from one stored option without an extra database query.<\/li>\n<li><strong>Probe refusal<\/strong>, on by default. A 403 for <code>.env<\/code> and other dot-files, copies of PHP files, configuration and log files, backups and dumps, other applications' admin paths and <code>.php<\/code> files that do not exist. Files your web server serves itself never reach it.<\/li>\n<li><strong>Address bans<\/strong>, observe mode first. An address that sends 3 probes in 10 minutes or asks for 20 missing pages in a minute is banned for an hour, and for a day on a repeat. Administrators (for a day after they last used wp-admin), verified search bots, Cloudflare and declared proxies and a never-ban list are never banned.<\/li>\n<li><strong>Bans tab<\/strong> with every ban, its evidence and an Unban button, the bans that would have happened in observe mode, and search-bot claims waiting for verification.<\/li>\n<li><strong>A dry run over your own logs.<\/strong> <code>wp bot-storm-radar replay --gate<\/code> shows what would have been refused in your access logs before you switch bans on.<\/li>\n<\/ul>\n\n<p><strong>Also<\/strong><\/p>\n\n<ul>\n<li>Reads web-server access logs (nginx or Apache combined format) as separate sources from WP-CLI, for traffic that never reaches WordPress.<\/li>\n<li>WooCommerce request classes (cart, checkout, wc-ajax) when WooCommerce is active.<\/li>\n<li>Counters live in the persistent object cache or in APCu, with a transient fallback. One of the first two is strongly recommended.<\/li>\n<\/ul>\n\n<h3>External services<\/h3>\n\n<p>The plugin ships with two public address lists and uses them as they are. It makes no HTTP request to an outside service unless you ask it to: switch on <strong>Address lists<\/strong> on the Settings tab to download both lists once a day from WordPress cron, or click <strong>Download address lists now<\/strong>. A download sends nothing about your visitors. Like any HTTP request, it shows the service your server's IP address and a user agent.<\/p>\n\n<ul>\n<li><strong>Cloudflare address ranges<\/strong>, from <code>https:\/\/www.cloudflare.com\/ips-v4<\/code> and <code>https:\/\/www.cloudflare.com\/ips-v6<\/code>. The plugin needs them to tell a request that really came through Cloudflare from one that only claims to. The request carries the WordPress default user agent, which names your site's address. The bundled copy is used until the first download and whenever a download fails. The service is provided by Cloudflare, see its <a href=\"https:\/\/www.cloudflare.com\/website-terms\/\">terms<\/a> and <a href=\"https:\/\/www.cloudflare.com\/privacypolicy\/\">privacy policy<\/a>.<\/li>\n<li><strong>DuckDuckBot address list<\/strong>, from <code>https:\/\/duckduckgo.com\/duckduckbot.json<\/code>. The plugin needs it to verify visitors that claim to be DuckDuckBot. The request carries the user agent <code>BotStormRadar\/<\/code> followed by the plugin version. The bundled copy is used until the first download and whenever a download fails. The service is provided by DuckDuckGo, see its <a href=\"https:\/\/duckduckgo.com\/terms\">terms<\/a> and <a href=\"https:\/\/duckduckgo.com\/privacy\">privacy policy<\/a>.<\/li>\n<\/ul>\n\n<p>The DNS check of search bots is off by default as well. Switch on <strong>Search bot check<\/strong> on the Settings tab to verify visitors that claim to be Googlebot, Bingbot, Applebot or Yandex: the plugin then asks your server's own DNS resolver for the host name of such an address, and looks that host name up to confirm it points back to the same address. Whether your resolver answers from its cache or asks other DNS servers, which then see the address, depends on your server's configuration. With the check off, no lookup is made and those visitors are never banned. The same lookups run once when you ask for them on the command line with <code>wp bot-storm-radar replay --gate --verify-bots<\/code>. The plugin has no telemetry service.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>bot-storm-radar<\/code> folder to <code>\/wp-content\/plugins\/<\/code>, or install the plugin from the Plugins screen.<\/li>\n<li>Activate it.<\/li>\n<li>Open <strong>Bot Storm Radar<\/strong> in wp-admin. Leave it running for a week so the baseline can learn, then review the thresholds on the Settings tab.<\/li>\n<li>Before you switch address bans to enforce, look at the Bans tab after a few days, or replay your access logs with <code>wp bot-storm-radar replay --gate<\/code>.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20it%20block%20a%20bot%20swarm%3F\"><h3>Does it block a bot swarm?<\/h3><\/dt>\n<dd><p>Not yet. The radar detects a swarm and tells you. What the plugin refuses today are scanner probes, for every visitor, and single addresses that tripped a ban once you switched bans to enforce.<\/p><\/dd>\n<dt id=\"what%20is%20observe%20mode%3F\"><h3>What is observe mode?<\/h3><\/dt>\n<dd><p>Address bans start in observe mode. An address that would have been banned is listed on the Bans tab with the requests that caused it, and nobody is refused. When the list looks right, switch to enforce on the Settings tab.<\/p><\/dd>\n<dt id=\"can%20it%20lock%20me%20or%20a%20search%20engine%20out%3F\"><h3>Can it lock me or a search engine out?<\/h3><\/dt>\n<dd><p>Administrators, for a day after they last used wp-admin, verified search bots, Cloudflare and declared proxies, and the addresses on your never-ban list are never banned. Put your own address on the never-ban list if you may stay away from wp-admin longer. An address that claims to be a search bot is verified before anything happens to it; while the Search bot check is off, an address claiming to be Googlebot, Bingbot, Applebot or Yandex is never banned.<\/p><\/dd>\n<dt id=\"how%20do%20i%20switch%20the%20refusals%20off%20without%20wp-admin%3F\"><h3>How do I switch the refusals off without wp-admin?<\/h3><\/dt>\n<dd><p>Rename or delete the <code>bot-storm-radar<\/code> folder in <code>wp-content\/plugins\/<\/code> by SFTP or in your host's file manager. WordPress then stops loading the plugin, and nothing is refused.<\/p><\/dd>\n<dt id=\"does%20it%20work%20behind%20cloudflare%20or%20another%20proxy%3F\"><h3>Does it work behind Cloudflare or another proxy?<\/h3><\/dt>\n<dd><p>Yes. Cloudflare is recognized by its published address ranges. Another proxy has to be declared on the Settings tab, and the plugin tells you when it sees one that is not declared.<\/p><\/dd>\n<dt id=\"does%20it%20need%20an%20object%20cache%3F\"><h3>Does it need an object cache?<\/h3><\/dt>\n<dd><p>No, but a persistent object cache (Redis, Memcached) or APCu is strongly recommended. Without one the counters fall back to transients in the database, and the Radar screen warns about it.<\/p><\/dd>\n<dt id=\"does%20it%20write%20files%3F\"><h3>Does it write files?<\/h3><\/dt>\n<dd><p>No. Settings, bans, minute history and the refusal rules are stored in the database.<\/p><\/dd>\n<dt id=\"does%20it%20track%20visitors%3F\"><h3>Does it track visitors?<\/h3><\/dt>\n<dd><p>No. It sets no cookies and has no telemetry, so nothing about your visitors is sent to the plugin's author or any other service. The only lookups that involve a visitor's address are the DNS checks of visitors that claim to be search bots, which run only if you switch them on (see External services). To tell real browsers from bots, every front-end page asks your own site for a 1-pixel image and runs one line of JavaScript that requests it once more; both requests only add to the counts of the current minute.<\/p>\n\n<p>Visitor addresses are kept only as long as the detection needs them: per-minute counters expire after 25 minutes, and the minute history of the last 25 hours keeps totals plus the busiest addresses of each minute (at most 20, each with 10 or more requests in that minute). An address that tripped a ban is stored with the requests that caused it (paths and user agent) until 30 days after its ban ended, the list of would-be bans keeps the latest 200 addresses, an address claiming to be a search bot waits at most a day for its check, and the addresses banned in the last hour are kept for the digest mail until the next ban replaces them. Administrator addresses are remembered for a day so they are never banned, search-bot checks for a day, and a suspected proxy address until you trust or dismiss it. Uninstalling the plugin deletes all of it.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.5.0<\/h4>\n\n<ul>\n<li>The DNS check of visitors that claim to be Googlebot, Bingbot, Applebot or Yandex runs only when you switch on Search bot check on the Settings tab. Off by default; with it off, those visitors are never banned.<\/li>\n<li>The admin-ajax, login, XML-RPC, comment and cron paths are taken from WordPress, so a moved admin or login page is recognized.<\/li>\n<\/ul>\n\n<h4>0.4.0<\/h4>\n\n<ul>\n<li>Probes and banned addresses are refused inside the plugin, before a page is built. The plugin writes no files.<\/li>\n<li>The Cloudflare and DuckDuckBot address lists are downloaded only when you switch on Address lists on the Settings tab. Off by default.<\/li>\n<li>Every request value the plugin reads is sanitized where it is read.<\/li>\n<li>The beacon script and the admin styles are enqueued.<\/li>\n<\/ul>\n\n<p>The full history is in <a href=\"https:\/\/github.com\/ProWoos-Devs\/bot-storm-radar\/blob\/main\/CHANGELOG.md\">CHANGELOG.md<\/a>.<\/p>","raw_excerpt":"Sees the bot swarms that per-address tools miss, says in plain words when a storm is running, and refuses scanner probes before a page is built.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/gu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/382952","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/gu.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/gu.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=382952"}],"author":[{"embeddable":true,"href":"https:\/\/gu.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/rafaelminuesa"}],"wp:attachment":[{"href":"https:\/\/gu.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=382952"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/gu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=382952"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/gu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=382952"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/gu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=382952"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/gu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=382952"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/gu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=382952"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}