Standard Django middleware, placed high in MIDDLEWARE so it runs before sessions and authentication touch the request.
Placement is the whole game in Django. Middleware runs top-down, so bot screening belongs above SessionMiddleware and AuthenticationMiddleware — otherwise every request creates a session row and a database hit before it is rejected, which is exactly the cost you were trying to avoid. Above those, a blocked request costs one function call and one HTTP round trip.
yourapp/middleware.py
Full endpoint reference and an interactive tester are in the API docs. Get a key from the free tier — no card required.
Anonymous bots that fetch every URL create a session row per request. Django makes this easy to miss until the session table is the largest thing in your database.
Automated sweeps for /admin, /wp-login.php and other known paths, generating constant noise in your logs and occasional indexing of anything left unauthenticated.
Public forms without a CAPTCHA are trivially scriptable, and DRF endpoints can be enumerated cheaply if the URL scheme is predictable.
Above SessionMiddleware. Anything below it has already paid the session cost by the time the verdict arrives.
It is deliberate. A short timeout with a fail-open fallback keeps your worst-case request latency bounded. ZeroBot’s median is under 50ms, so the timeout is a safety valve rather than the normal path.
Yes — middleware runs before DRF views, so API endpoints are covered by the same guard.
Free tier, real verdicts, and documentation with a built-in tester.
Get started free →