Skip to main content

Python client for Esper bot detection API

Project description

Esper Python Client

Lightweight Python client library for Esper bot detection API.

Installation

pip install esper-py-client

Quick Start

from esper import EsperClient, EsperConfig, MitigationRequest, MitigationAction

# Initialize client
config = EsperConfig(api_key="your-api-key")
client = EsperClient(config)

# Check if request should be mitigated
request = MitigationRequest(
    ip="192.168.1.1",
    user_agent="Mozilla/5.0...",
    path="/api/endpoint",
    method="POST"
)

response = client.check_mitigation(request)

if response.action == MitigationAction.BLOCK:
    # Block the request
    print("Request blocked:", response.reason)
elif response.action == MitigationAction.CHALLENGE:
    # Present challenge to user
    print("Challenge required:", response.challenge)
else:
    # Allow the request
    print("Request allowed")

Async Support

import asyncio
from esper import AsyncEsperClient, EsperConfig, MitigationRequest

async def check_request():
    config = EsperConfig(api_key="your-api-key")

    async with AsyncEsperClient(config) as client:
        request = MitigationRequest(ip="192.168.1.1")
        response = await client.check_mitigation(request)
        return response

# Run async function
response = asyncio.run(check_request())

Configuration

from esper import EsperConfig

config = EsperConfig(
    api_key="your-api-key",              # Required
    api_url="https://api.esperr.com",    # Optional
    beacon_url="https://beacon.esperr.com", # Optional
    timeout=30.0,                         # Optional (seconds)
    max_retries=3,                        # Optional
    retry_delay=1.0                       # Optional (seconds)
)

API Reference

Check Mitigation

from esper import MitigationRequest

request = MitigationRequest(
    ip="192.168.1.1",
    user_agent="Mozilla/5.0...",
    path="/api/endpoint",
    method="POST",
    headers={"X-Custom": "value"},
    metadata={"user_id": "123"}
)

response = client.check_mitigation(request)
print(f"Action: {response.action}")
print(f"Score: {response.score}")
print(f"Reason: {response.reason}")

Verify Challenge

# Verify user's challenge response
is_valid = client.verify_challenge(
    token="challenge-token",
    response="user-response"
)

if is_valid:
    print("Challenge passed")
else:
    print("Challenge failed")

Send Beacon Event

from esper import BeaconEvent

# Send telemetry event
event = BeaconEvent(
    type="page_view",
    ip="192.168.1.1",
    user_agent="Mozilla/5.0...",
    session_id="session-123",
    data={"page": "/home", "referrer": "/login"}
)

client.send_beacon_event(event)

Get Usage Statistics

# Get API usage
usage = client.get_usage()
print(f"Total requests: {usage.requests}")
print(f"Blocked: {usage.blocked}")
print(f"Challenged: {usage.challenged}")
print(f"Allowed: {usage.allowed}")

Django Integration

# middleware.py
from django.http import JsonResponse
from esper import EsperClient, EsperConfig, MitigationRequest

class EsperMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        config = EsperConfig(api_key=settings.ESPER_API_KEY)
        self.client = EsperClient(config)

    def __call__(self, request):
        # Check mitigation
        mitigation_request = MitigationRequest(
            ip=self.get_client_ip(request),
            user_agent=request.META.get('HTTP_USER_AGENT'),
            path=request.path,
            method=request.method
        )

        try:
            response = self.client.check_mitigation(mitigation_request)

            if response.action == MitigationAction.BLOCK:
                return JsonResponse({"error": "Access denied"}, status=403)
            elif response.action == MitigationAction.CHALLENGE:
                return JsonResponse({"challenge": response.challenge.dict()}, status=429)
        except Exception as e:
            # Log error and allow request on failure
            logger.error(f"Esper error: {e}")

        return self.get_response(request)

    def get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            return x_forwarded_for.split(',')[0]
        return request.META.get('REMOTE_ADDR')

FastAPI Integration

from fastapi import FastAPI, Request, HTTPException
from esper import AsyncEsperClient, EsperConfig, MitigationRequest

app = FastAPI()
config = EsperConfig(api_key="your-api-key")
esper = AsyncEsperClient(config)

@app.middleware("http")
async def esper_middleware(request: Request, call_next):
    # Check mitigation
    mitigation_request = MitigationRequest(
        ip=request.client.host,
        user_agent=request.headers.get("user-agent"),
        path=request.url.path,
        method=request.method
    )

    try:
        response = await esper.check_mitigation(mitigation_request)

        if response.action == MitigationAction.BLOCK:
            raise HTTPException(status_code=403, detail="Access denied")
        elif response.action == MitigationAction.CHALLENGE:
            return JSONResponse(
                status_code=429,
                content={"challenge": response.challenge.dict()}
            )
    except Exception as e:
        # Log error and continue
        logger.error(f"Esper error: {e}")

    return await call_next(request)

Error Handling

from esper import (
    EsperAPIError,
    EsperConnectionError,
    EsperTimeoutError
)

try:
    response = client.check_mitigation(request)
except EsperAPIError as e:
    print(f"API error: {e.message}")
    print(f"Status code: {e.status_code}")
    print(f"Error code: {e.error_code}")
except EsperConnectionError as e:
    print(f"Connection error: {e}")
except EsperTimeoutError as e:
    print(f"Timeout error: {e}")

Testing

# Install development dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=esper

# Type checking
mypy src/esper

# Linting
ruff check src/esper

# Formatting
black src/esper
isort src/esper

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

esper_py_client-0.1.0.tar.gz (9.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

esper_py_client-0.1.0-py3-none-any.whl (8.0 kB view details)

Uploaded Python 3

File details

Details for the file esper_py_client-0.1.0.tar.gz.

File metadata

  • Download URL: esper_py_client-0.1.0.tar.gz
  • Upload date:
  • Size: 9.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for esper_py_client-0.1.0.tar.gz
Algorithm Hash digest
SHA256 80a3ef3746453537adbdc93af35acc4b3d759d75bd27699b8bf346cf97e8e56d
MD5 4efbe84bbc2d962d96b2c07efd88cd83
BLAKE2b-256 44be5972c6375dd27a71a747a788600f4d9d05f238df8c3a531cfefb32446ec6

See more details on using hashes here.

File details

Details for the file esper_py_client-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: esper_py_client-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for esper_py_client-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3e185d969ae5e9e133b952adce722db13091d83e34097c73c4ba106ad95c625f
MD5 f0a5607c34ec051e1308911d8a6e4230
BLAKE2b-256 f5b470c3b14fe36dc1db597fb4b52defa3e596f774b8dd0c4d12af7e041676bd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page