Skip to content

Real blocking (server-side)

Detect vs. block — the difference that matters

The JavaScript snippet runs in the visitor's browser, after your page already loaded. It's great at seeing and trapping bots, but it has a real limit: most scrapers (curl, Python, Scrapy, headless tools with JS disabled) never execute page JavaScript at all, so the snippet never runs for them — and even when it does run, your content was already delivered.

The integrations on this page run on your own server or edge, before a response is ever sent — stopping non-JS scrapers too. All of them are one-time, site-wide installs — activate a plugin, add one middleware file, or set one config value, and every page is covered. None of them need to be added per-page.

How blocking behaves:

  • A confirmed-bad IP (on your blocklist) or a hit on a decoy path gets a plain 403 — no content, ever.
  • In cookie mode, a visitor without a valid signed cookie gets a brief "Checking your browser" page instead of your content. Real visitors pass automatically in a few seconds (the Botfighter snippet on that page verifies them and reloads); scrapers that don't run JavaScript stay stuck there with zero site content.

They all work the same underlying way: no DNS change, no proxy, no rerouted traffic. Your server (or edge function) makes a small, cached, fail-open call to Botfighter's public blocklist — if that call ever fails or times out, the request is allowed through. Botfighter never sees your traffic directly.

Which mode should I use?

Every integration takes a mode. Pick based on whether your pages need to be indexed by search engines:

ModeWhat it enforcesUse it when
ipConfirmed-bad IPs + decoy paths only. No owner token needed.Public, SEO-indexed sites (the safe default). Search crawlers, feed readers, and legitimate tools are never touched — only IPs already confirmed to be bots are blocked.
bothEverything in ip, plus requires a valid signed cookie for every visitor.Gated / non-indexed content (app dashboards, member areas, staging). Stronger, but see the warning below.
cookieSigned cookie only (no IP blocklist).Rarely — when you specifically don't want the shared IP list.
detectNothing — never blocks.Testing the install without enforcing.

both/cookie mode blocks search engines

The signed cookie is only issued to visitors classified as human. Search-engine crawlers (Googlebot, Bingbot, etc.) are classified as good bots, not human — so they never receive a cookie and will be stopped at the "Checking your browser" page. On a publicly-indexed site this will deindex you. Use ip mode for anything you want in search results; reserve both/cookie for content that should never be indexed anyway.

Choose your platform

PlatformInstallMechanism
WordPressGuide belowPlugin, activate once
Any PHP appGuide belowOne require, one time
Node.js / Express / Next.jsGuide belowOne middleware, one time
Cloudflare PagesGuide belowOne Pages Function file
VercelGuide belowOne middleware.ts file
NetlifyGuide belowOne Edge Function file
Shopify, Wix, Squarespace, standard BigCommerceNot availableThese platforms don't give merchants server or edge code execution — detection (the snippet) is all that's possible. See Server-side blocking coverage below.

WordPress

  1. Download the plugin: botfighter-wordpress-plugin.zip
  2. In wp-admin: Plugins → Add New → Upload Plugin → choose the zip → Install NowActivate.
  3. Go to Settings → Botfighter.
  4. Enter your Site ID and Owner Token (from your dashboard), and choose a block mode — ip for a public/SEO-indexed site, both only for gated content (see Which mode should I use? above).

That's it — every page is protected immediately, nothing to add per-page. If your host runs a full-page cache (WP Engine, Kinsta, Pantheon, Flywheel, or any LiteSpeed Cache host like Hostinger), the plugin will show an admin warning, since a cached page can be served without ever running PHP. See Cloudflare Pages below for an edge-level option that isn't affected by PHP-level caching.

PHP (any PHP app)

  1. Download botfighter.php and place it anywhere in your project.
  2. At the very top of your shared bootstrap file (the one file every request already goes through — e.g. config.php, wp-config.php, your framework's front controller), before any output:
php
define('BF_SITE_ID', 'YOUR-SITE-ID');
define('BF_MODE',    'ip');   // recommended — no token, safe for SEO. See "Which mode?" above.
require '/path/to/botfighter.php';

// For gated (non-indexed) content, use cookie enforcement instead — needs the owner token:
//   define('BF_OWNER_TOKEN', 'YOUR_OWNER_TOKEN');
//   define('BF_MODE', 'both');

One edit, one time — every request through that bootstrap file is now protected.

Node.js / Express / Next.js

  1. Download botfighter-middleware.js (and the type definitions if using TypeScript) into your project, e.g. as lib/botfighter-middleware.js.
  2. Wire it in once, at your app's setup:
js
const { createBotfighter } = require('./lib/botfighter-middleware')
const bf = createBotfighter({
  siteId: 'YOUR-SITE-ID',
  mode: 'ip',              // recommended — no token, safe for SEO. See "Which mode?" above.
  // For gated content, use cookie enforcement (blocks search crawlers):
  //   ownerToken: 'YOUR_OWNER_TOKEN', mode: 'both',
})
app.use(bf.middleware)     // returns 403 before your routes run

For frameworks without Express-style (req, res, next) middleware (edge runtimes, Next.js route handlers), use bf.check(request) instead — it takes a standard Fetch API Request and returns { blocked, reason }. When the reason is no_valid_cookie, respond with bf.challengeResponse() (the browser-check page), not a bare 403 — a bare 403 would lock out real first-time visitors, since the cookie can only be obtained from a served page:

js
const result = await bf.check(request)
if (result.blocked) {
  return result.reason === 'no_valid_cookie'
    ? bf.challengeResponse()
    : new Response('Access denied.', { status: 403 })
}

Zero dependencies — this is a single file, not an npm package, so there's nothing to install.

Cloudflare Pages

Runs before your Cloudflare Pages site's origin is even asked — the strongest tier short of a full reverse proxy (which Botfighter deliberately doesn't do).

  1. Download cloudflare-pages-middleware.js.
  2. Copy it to functions/_middleware.js in your Pages project.
  3. Set SITE_ID at the top of the file to your Botfighter site ID.
  4. Deploy as normal (wrangler pages deploy or your existing Git integration).

This one file also verifies that a visitor claiming to be Googlebot/Bingbot/etc. actually resolves back to that crawler's real network (rDNS), and enforces any bots you've blocked in robots.txt — not just the IP blocklist.

Vercel

  1. Download vercel-middleware.ts.
  2. Copy it to middleware.ts at your project root (same level as package.json). On Next.js 16+, use proxy.ts with export function proxy instead — everything else is identical.
  3. Set SITE_ID at the top of the file.
  4. Deploy as normal.

No npm install needed — it only uses next/server, already part of Next.js.

Netlify

  1. Download netlify-edge-function.js.
  2. Copy it to netlify/edge-functions/botfighter-guard.js.
  3. Set SITE_ID at the top of the file.
  4. Deploy as normal — Netlify auto-discovers files in that folder.

Platform coverage

Not every platform allows server or edge code at all. If yours isn't listed above as supporting real blocking, the JavaScript snippet (detection only) is what's available — this is a platform limitation, not something Botfighter can add around. Ask if you're not sure where your platform falls.


Need help? Check the dashboard for your live signal feed.