> For the complete documentation index, see [llms.txt](https://docs.stopbot.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.stopbot.net/v2/service-guides/stopbot-v2/blocker.md).

# Blocker

The Blocker service helps identify whether a website visitor is a real user, bot, crawler, proxy, VPN, Tor exit node, suspicious hostname, or visitor matching your own allow/block rules.

### Endpoint Used

```
GET https://api.stopbot.net/services/blocker
```

### How It Works

1. Your application receives a visitor request.
2. The integration sends the visitor IP, user agent, and current URL to STOPBOT V2.
3. STOPBOT returns a decision.
4. Your application allows the visitor, redirects the visitor, or returns an HTTP error page.

### Required Parameters

| Parameter | Description           |
| --------- | --------------------- |
| `apikey`  | Your STOPBOT API key  |
| `ip`      | Visitor IP address    |
| `ua`      | Visitor user agent    |
| `url`     | Current requested URL |

> **Security note:** Keep your API key on the backend server. Do not publish it in browser-only JavaScript, mobile apps, or public repositories.

> **Proxy note:** Only trust `CF-Connecting-IP` or `X-Forwarded-For` when your application is behind a trusted proxy such as Cloudflare or your own reverse proxy.

### Decision Field

This guide uses the V2 response field:

```
blockAccess
```

If `blockAccess` is `1`, the integration applies the configured block action.

Always use `blockAccess` as the allow/block decision field. Do not use `isBot` as the final access decision. `isBot` is a visitor classification signal, while `blockAccess` tells your integration whether the block action should be applied.

### Common Actions

| Action                          | Behavior                                                                   |
| ------------------------------- | -------------------------------------------------------------------------- |
| Monitor only                    | Send requests to STOPBOT and allow the visitor regardless of `blockAccess` |
| Redirect blocked visitors       | Redirect when `blockAccess` is `1`                                         |
| Return 404 for blocked visitors | Return an HTTP `404` response when `blockAccess` is `1`                    |

### Environment Variables

The examples use these environment variables:

| Variable               | Required | Description                                                                |
| ---------------------- | -------- | -------------------------------------------------------------------------- |
| `STOPBOT_API_KEY`      | Yes      | Your STOPBOT API key                                                       |
| `STOPBOT_PROTECTION`   | No       | Set to `0` for monitor-only mode. Any other value enables the block action |
| `STOPBOT_REDIRECT_URL` | No       | Redirect target for blocked visitors. Leave empty to return `404`          |

### cURL Test

Use this request to test the endpoint before adding it to your application:

```bash
curl "https://api.stopbot.net/services/blocker?apikey={API_KEY}&ip=1.1.1.1&ua=Mozilla%2F5.0&url=https%3A%2F%2Fexample.com%2F"
```

### PHP

Create a file named:

```
stopbot-blocker.php
```

Paste this code:

```php
<?php
/*
 * STOPBOT V2 - Blocker Integration
 * API: https://api.stopbot.net/services/blocker
 */

$StopbotApiKey = getenv("STOPBOT_API_KEY") ?: "________________________________";

// 0 = monitor only
// 1 = apply block action when STOPBOT returns blockAccess = 1
$StopbotProtection = getenv("STOPBOT_PROTECTION") === "0" ? 0 : 1;

// Leave empty to return HTTP 404 for blocked visitors.
$StopbotRedirectURL = getenv("STOPBOT_REDIRECT_URL") ?: "";

function stopbot_client_ip(): string
{
    if (!empty($_SERVER["HTTP_CF_CONNECTING_IP"]) && filter_var($_SERVER["HTTP_CF_CONNECTING_IP"], FILTER_VALIDATE_IP)) {
        return $_SERVER["HTTP_CF_CONNECTING_IP"];
    }

    if (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
        $first = trim(explode(",", $_SERVER["HTTP_X_FORWARDED_FOR"])[0]);
        if (filter_var($first, FILTER_VALIDATE_IP)) {
            return $first;
        }
    }

    return $_SERVER["REMOTE_ADDR"] ?? "0.0.0.0";
}

function stopbot_current_url(): string
{
    $scheme = (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off") ? "https://" : "http://";
    return $scheme . ($_SERVER["HTTP_HOST"] ?? "") . ($_SERVER["REQUEST_URI"] ?? "/");
}

function stopbot_blocker_request(string $apiKey): ?array
{
    $endpoint = "https://api.stopbot.net/services/blocker";

    $query = http_build_query([
        "apikey" => $apiKey,
        "ip" => stopbot_client_ip(),
        "ua" => $_SERVER["HTTP_USER_AGENT"] ?? "",
        "url" => stopbot_current_url(),
    ]);

    $ch = curl_init($endpoint . "?" . $query);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => "GET",
        CURLOPT_ENCODING => "gzip, deflate",
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_HTTPHEADER => ["Accept: application/json"],
    ]);

    $response = curl_exec($ch);
    $curlError = curl_error($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($response === false || $httpCode < 200 || $httpCode >= 300) {
        error_log("[STOPBOT V2] Blocker request failed. HTTP {$httpCode}. {$curlError}");
        return null;
    }

    $json = json_decode($response, true);
    return is_array($json) ? $json : null;
}

$stopbotResponse = stopbot_blocker_request($StopbotApiKey);

if (($stopbotResponse["status"] ?? "") === "success") {
    $shouldBlock = (int)($stopbotResponse["blockAccess"] ?? 0) === 1;

    if ($StopbotProtection === 1 && $shouldBlock) {
        if (!empty($StopbotRedirectURL)) {
            header("Location: " . $StopbotRedirectURL, true, 302);
            exit;
        }

        http_response_code(404);
        exit;
    }
}
```

Add it to the top of your main PHP entry file:

```php
<?php require_once __DIR__ . "/stopbot-blocker.php"; ?>
```

### Node.js

This example uses Express and the built-in `fetch` available in modern Node.js versions.

Create a file named:

```
stopbot-blocker.js
```

Paste this code:

```js
const STOPBOT_API_KEY = process.env.STOPBOT_API_KEY || "";
const STOPBOT_REDIRECT_URL = process.env.STOPBOT_REDIRECT_URL || "";
const STOPBOT_PROTECTION = process.env.STOPBOT_PROTECTION || "1";
const STOPBOT_ENDPOINT = "https://api.stopbot.net/services/blocker";

function clientIp(req) {
  const cfIp = req.headers["cf-connecting-ip"];
  if (typeof cfIp === "string" && cfIp.length > 0) {
    return cfIp;
  }

  const forwardedFor = req.headers["x-forwarded-for"];
  if (typeof forwardedFor === "string" && forwardedFor.length > 0) {
    return forwardedFor.split(",")[0].trim();
  }

  return (req.socket.remoteAddress || "0.0.0.0").replace(/^::ffff:/, "");
}

function currentUrl(req) {
  const host = req.get("host") || "";
  const protocol = req.protocol || "http";
  return `${protocol}://${host}${req.originalUrl || req.url || "/"}`;
}

async function stopbotBlockerRequest(req) {
  const params = new URLSearchParams({
    apikey: STOPBOT_API_KEY,
    ip: clientIp(req),
    ua: req.get("user-agent") || "",
    url: currentUrl(req),
  });

  const response = await fetch(`${STOPBOT_ENDPOINT}?${params.toString()}`, {
    method: "GET",
    headers: { Accept: "application/json" },
    signal: AbortSignal.timeout(10000),
  });

  if (!response.ok) {
    console.error(`[STOPBOT V2] Blocker request failed. HTTP ${response.status}`);
    return null;
  }

  return response.json();
}

async function stopbotBlocker(req, res, next) {
  if (!STOPBOT_API_KEY) {
    return next();
  }

  try {
    const result = await stopbotBlockerRequest(req);
    const shouldBlock = result?.status === "success" && Number(result.blockAccess || 0) === 1;

    if (STOPBOT_PROTECTION === "1" && shouldBlock) {
      if (STOPBOT_REDIRECT_URL) {
        return res.redirect(302, STOPBOT_REDIRECT_URL);
      }

      return res.sendStatus(404);
    }
  } catch (error) {
    console.error("[STOPBOT V2] Blocker request failed.", error);
  }

  return next();
}

module.exports = stopbotBlocker;
```

Call it as the first middleware in your main file:

```js
const express = require("express");
const stopbotBlocker = require("./stopbot-blocker");

const app = express();

app.use(stopbotBlocker);

app.get("/", (req, res) => {
  res.send("Protected by STOPBOT V2 Blocker");
});

app.listen(3000);
```

### Python

This example uses Flask and Python standard library HTTP utilities.

Create a file named:

```
stopbot_blocker.py
```

Paste this code:

```python
import json
import os
import urllib.parse
import urllib.request

from flask import abort, current_app, redirect, request

STOPBOT_API_KEY = os.environ.get("STOPBOT_API_KEY", "")
STOPBOT_REDIRECT_URL = os.environ.get("STOPBOT_REDIRECT_URL", "")
STOPBOT_PROTECTION = os.environ.get("STOPBOT_PROTECTION", "1")
STOPBOT_ENDPOINT = "https://api.stopbot.net/services/blocker"


def client_ip():
    cf_ip = request.headers.get("CF-Connecting-IP")
    if cf_ip:
        return cf_ip

    forwarded_for = request.headers.get("X-Forwarded-For")
    if forwarded_for:
        return forwarded_for.split(",")[0].strip()

    return request.remote_addr or "0.0.0.0"


def current_url():
    return request.url


def stopbot_blocker_request():
    params = urllib.parse.urlencode({
        "apikey": STOPBOT_API_KEY,
        "ip": client_ip(),
        "ua": request.headers.get("User-Agent", ""),
        "url": current_url(),
    })

    api_request = urllib.request.Request(
        f"{STOPBOT_ENDPOINT}?{params}",
        headers={"Accept": "application/json"},
        method="GET",
    )

    try:
        with urllib.request.urlopen(api_request, timeout=10) as response:
            if response.status < 200 or response.status >= 300:
                current_app.logger.warning("STOPBOT V2 request failed. HTTP %s", response.status)
                return None

            return json.loads(response.read().decode("utf-8"))
    except Exception as error:
        current_app.logger.warning("STOPBOT V2 request failed: %s", error)
        return None


def register_stopbot_blocker(app):
    @app.before_request
    def stopbot_blocker_guard():
        if not STOPBOT_API_KEY:
            return None

        result = stopbot_blocker_request()
        should_block = (
            result
            and result.get("status") == "success"
            and int(result.get("blockAccess", 0)) == 1
        )

        if STOPBOT_PROTECTION == "1" and should_block:
            if STOPBOT_REDIRECT_URL:
                return redirect(STOPBOT_REDIRECT_URL, code=302)

            abort(404)

        return None
```

Call it near the top of your main Flask file before defining routes:

```python
from flask import Flask
from stopbot_blocker import register_stopbot_blocker

app = Flask(__name__)
register_stopbot_blocker(app)

@app.route("/")
def index():
    return "Protected by STOPBOT V2 Blocker"
```

### Go

This example uses the standard `net/http` package.

The middleware is registered once when the server starts, but it runs on every incoming visitor request. The reusable `stopbotHTTPClient` below is only the server-side HTTP client used to call the STOPBOT API.

Create a file named:

```
stopbot_blocker.go
```

Paste this code:

```go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

const stopbotEndpoint = "https://api.stopbot.net/services/blocker"

var stopbotHTTPClient = &http.Client{Timeout: 10 * time.Second}

type blockerResponse struct {
	Status      string `json:"status"`
	BlockAccess int    `json:"blockAccess"`
}

func visitorIP(r *http.Request) string {
	if ip := r.Header.Get("CF-Connecting-IP"); net.ParseIP(ip) != nil {
		return ip
	}

	if forwardedFor := r.Header.Get("X-Forwarded-For"); forwardedFor != "" {
		first := strings.TrimSpace(strings.Split(forwardedFor, ",")[0])
		if net.ParseIP(first) != nil {
			return first
		}
	}

	host, _, err := net.SplitHostPort(r.RemoteAddr)
	if err == nil && net.ParseIP(host) != nil {
		return host
	}

	return "0.0.0.0"
}

func currentURL(r *http.Request) string {
	scheme := "http"
	if r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https" {
		scheme = "https"
	}

	return scheme + "://" + r.Host + r.URL.RequestURI()
}

func stopbotBlockerRequest(ctx context.Context, apiKey string, r *http.Request) (*blockerResponse, error) {
	values := url.Values{}
	values.Set("apikey", apiKey)
	values.Set("ip", visitorIP(r))
	values.Set("ua", r.UserAgent())
	values.Set("url", currentURL(r))

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, stopbotEndpoint+"?"+values.Encode(), nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Accept", "application/json")

	resp, err := stopbotHTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, fmt.Errorf("STOPBOT V2 request failed with HTTP %d", resp.StatusCode)
	}

	var result blockerResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, err
	}

	return &result, nil
}

func StopbotBlocker(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		apiKey := os.Getenv("STOPBOT_API_KEY")
		if apiKey == "" {
			next.ServeHTTP(w, r)
			return
		}

		result, err := stopbotBlockerRequest(r.Context(), apiKey, r)
		if err != nil {
			log.Printf("[STOPBOT V2] %v", err)
			next.ServeHTTP(w, r)
			return
		}

		shouldBlock := result.Status == "success" && result.BlockAccess == 1
		if os.Getenv("STOPBOT_PROTECTION") != "0" && shouldBlock {
			if redirectURL := os.Getenv("STOPBOT_REDIRECT_URL"); redirectURL != "" {
				http.Redirect(w, r, redirectURL, http.StatusFound)
				return
			}

			http.NotFound(w, r)
			return
		}

		next.ServeHTTP(w, r)
	})
}
```

Call it in your `main.go` before starting the server:

```go
package main

import (
	"log"
	"net/http"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte("Protected by STOPBOT V2 Blocker"))
	})

	log.Fatal(http.ListenAndServe(":8080", StopbotBlocker(mux)))
}
```

### Test The Integration

1. Set `STOPBOT_API_KEY` in your server environment.
2. Start your application.
3. Open your website in a browser.
4. Confirm the page still loads normally.
5. Check your application logs for STOPBOT connection errors.
6. Open the STOPBOT panel and confirm visitor statistics are being recorded.

### Recommended Failure Behavior

The examples above allow the visitor when the STOPBOT API request fails. This keeps your website available during temporary network or service issues.

If your security policy requires blocking on API failure, change the error branch carefully and test it in staging first.

### Response Fields Used

| Field            | Usage                                                                                       |
| ---------------- | ------------------------------------------------------------------------------------------- |
| `status`         | Confirms the API request was processed successfully                                         |
| `blockAccess`    | Main allow/block decision field                                                             |
| `isBot`          | Visitor classification signal only. Do not use this field as the final allow/block decision |
| `detectActivity` | Optional reason field for logs or debugging                                                 |

### V1 Difference

Legacy V1 examples use:

```
IPStatus.BlockAccess
```

V2 uses:

```
blockAccess
```
