Integrations → Python

Python integration

Flask decorator, Django middleware, FastAPI dependency. No SDK, requests only.

Flask decorator

import os, requests
from functools import wraps
from flask import request, abort

LICENSE = os.environ['ZEROBOT_KEY']
DOMAIN  = os.environ['ZEROBOT_DOMAIN']

def zerobot(f):
    @wraps(f)
    def wrapped(*args, **kw):
        ip = request.headers.get('CF-Connecting-IP') or request.remote_addr
        try:
            r = requests.get('https://api.zerobot.info/v3/openapi', params={
                'license':   LICENSE,
                'ip':        ip,
                'domain':    DOMAIN,
                'useragent': request.headers.get('User-Agent', ''),
            }, timeout=5)
            data = r.json() if r.ok else {}
        except requests.RequestException:
            data = {}   # fail open
        if data.get('is_bot'):
            abort(403, data.get('reason', 'bot'))
        return f(*args, **kw)
    return wrapped
# app.py
from flask import Flask
from zerobot import zerobot

app = Flask(__name__)

@app.route('/')
@zerobot
def home():
    return 'Hello, human!'

app.run()

Django middleware

# zerobot_middleware.py
import os, requests
from django.http import HttpResponseForbidden

class ZeroBotMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.license      = os.environ['ZEROBOT_KEY']
        self.domain       = os.environ['ZEROBOT_DOMAIN']

    def __call__(self, request):
        ip = request.META.get('HTTP_CF_CONNECTING_IP') or request.META.get('REMOTE_ADDR', '')
        try:
            r = requests.get('https://api.zerobot.info/v3/openapi', params={
                'license':   self.license,
                'ip':        ip,
                'domain':    self.domain,
                'useragent': request.META.get('HTTP_USER_AGENT', ''),
            }, timeout=5).json()
            if r.get('is_bot'):
                return HttpResponseForbidden(f"Blocked: {r.get('reason')}")
        except requests.RequestException:
            pass  # fail open
        return self.get_response(request)
# settings.py
MIDDLEWARE = [
    # … other middleware …
    'zerobot_middleware.ZeroBotMiddleware',
]

FastAPI dependency (async)

import os, httpx
from fastapi import Depends, HTTPException, Request

LICENSE = os.environ['ZEROBOT_KEY']
DOMAIN  = os.environ['ZEROBOT_DOMAIN']

async def zerobot_guard(request: Request):
    ip = request.headers.get('cf-connecting-ip') or (request.client.host if request.client else '')
    async with httpx.AsyncClient(timeout=5) as client:
        try:
            r = await client.get('https://api.zerobot.info/v3/openapi', params={
                'license': LICENSE, 'ip': ip, 'domain': DOMAIN,
                'useragent': request.headers.get('user-agent', ''),
            })
            data = r.json() if r.status_code == 200 else {}
        except httpx.HTTPError:
            data = {}
    if data.get('is_bot'):
        raise HTTPException(status_code=403, detail=data.get('reason', 'bot'))

# Use on any route:
from fastapi import FastAPI

app = FastAPI()

@app.get('/', dependencies=[Depends(zerobot_guard)])
async def home():
    return {'msg': 'Hello, human!'}

Simple caching (in-memory)

import time

_cache = {}
_TTL   = 86400  # 24h

def _cached_screen(ip, fetcher):
    hit = _cache.get(ip)
    if hit and hit['exp'] > time.time():
        return hit['data']
    data = fetcher()
    _cache[ip] = {'data': data, 'exp': time.time() + _TTL}
    return data

For multi-worker deployments, replace the in-memory dict with Redis or Memcached.