Skip to main content

Invisible bot protection for FastAPI applications using Roundtable.ai Proof-of-Human detection

Project description

fastapi-roundtable

Invisible bot protection for FastAPI applications using Roundtable.ai Proof-of-Human detection.

PyPI version Python 3.9+ License: MIT

Overview

fastapi-roundtable is a FastAPI integration for Roundtable.ai Proof-of-Human bot detection. It provides backend session validation for protecting your FastAPI endpoints from automated bots and suspicious activity.

Roundtable uses behavioral biometrics and device analysis to detect bots with best-in-class accuracy (87% vs Google's 69% and Cloudflare's 33%). Unlike CAPTCHAs, it works invisibly in the background, providing a frictionless experience for legitimate users while blocking automated threats.

This library handles the backend validation piece, making it easy to verify session IDs generated by Roundtable's frontend JavaScript tracker.

How It Works

┌─────────────┐
│   Browser   │  1. Roundtable JS tracker monitors user behavior
│  (Frontend) │  2. Generates session ID based on behavioral analysis
└──────┬──────┘
       │ Session ID (form field, header, or body)
       ▼
┌─────────────┐
│   FastAPI   │  3. fastapi-roundtable validates session ID
│  (Backend)  │  4. Queries Roundtable API for risk score
└──────┬──────┘  5. Rejects high-risk sessions automatically
       │
       ▼
┌─────────────┐
│ Roundtable  │  Returns risk score (0-100)
│     API     │  Higher score = more suspicious
└─────────────┘

The result: Bots and automated attacks are blocked before they can exploit your system, while legitimate users never see a CAPTCHA or challenge.

Features

  • Async session validation using aiohttp for high performance
  • Multiple session ID sources - extract from form fields, HTTP headers, or request body
  • Configurable risk thresholds - set your own acceptable risk level
  • Type-safe - full type hints throughout
  • Environment variable support - secure API key management
  • FastAPI-native - uses dependency injection for clean integration

Prerequisites

Before using this library, you need:

  1. A Roundtable.ai account with Site Key and Secret Key
  2. Roundtable's JavaScript tracker installed on your frontend pages
  3. A FastAPI application

Installation

pip install fastapi-roundtable

Quick Start

1. Add Roundtable tracker to your frontend

<!DOCTYPE html>
<html>
<head>
    <title>Contact Form</title>
</head>
<body>
    <form method="POST" action="/contact">
        <!-- Hidden field for Roundtable session ID -->
        <input type="hidden" name="rt_session_id" id="rt_session_id" value="">

        <input type="text" name="name" placeholder="Your name" required>
        <input type="email" name="email" placeholder="Your email" required>
        <textarea name="message" placeholder="Your message" required></textarea>
        <button type="submit">Send</button>
    </form>

    <!-- Load Roundtable tracker -->
    <script src="https://cdn.roundtable.ai/v1/rt.js"
            data-site-key="YOUR_SITE_KEY"></script>

    <!-- Populate hidden field with session ID from sessionStorage -->
    <script>
        const interval = setInterval(() => {
            if (sessionStorage.getItem('rtSessionId')) {
                clearInterval(interval);
                document.getElementById("rt_session_id").value = sessionStorage.getItem('rtSessionId');
            }
        }, 500);
    </script>
</body>
</html>

The Roundtable tracker stores the session ID in sessionStorage.rtSessionId. The JavaScript code polls for this value and populates the hidden form field when available.

2. Protect your FastAPI endpoint

from fastapi import Depends, FastAPI
from fastapi_roundtable import Roundtable

app = FastAPI()

# Initialize Roundtable validator (do this once, reuse across endpoints)
roundtable = Roundtable(
    api_key="your_secret_key",  # or set ROUNDTABLE_API_KEY env var
    status_code=404,            # HTTP status to return on validation failure
    max_risk_score=50           # Maximum acceptable risk score (0-100)
)

@app.post("/contact", dependencies=[Depends(roundtable(form_field="rt_session_id"))])
async def contact_form(name: str, email: str, message: str):
    # This code only runs if session validation passes
    # Bots and high-risk sessions are automatically rejected
    return {"message": "Thank you for your message!"}

That's it! Your endpoint is now protected from bots.

Detailed Usage Examples

Form-Based Validation

Perfect for contact forms, signup pages, and user submissions:

from fastapi import Depends, FastAPI, Form
from fastapi_roundtable import Roundtable

app = FastAPI()
roundtable = Roundtable()

@app.post("/signup", dependencies=[Depends(roundtable(form_field="rt_session_id"))])
async def signup(
    username: str = Form(...),
    email: str = Form(...),
    password: str = Form(...)
):
    # Only legitimate users reach this code
    return {"status": "success"}

Header-Based Validation

Ideal for API endpoints and mobile applications:

@app.post("/api/submit", dependencies=[Depends(roundtable(http_header="X-Session-ID"))])
async def api_submit(data: dict):
    # Validate session from custom header
    return {"received": data}

Client sends request with header:

POST /api/submit
X-Session-ID: <roundtable_session_id>

Body-Based Validation

For JSON APIs where session ID is in the request payload:

@app.post("/api/create", dependencies=[Depends(roundtable(body_field="session_id"))])
async def create_resource(data: dict):
    return {"created": True}

Client sends JSON:

{
  "session_id": "<roundtable_session_id>",
  "name": "Resource name",
  "data": {...}
}

Custom Error Handling

Customize the response when validation fails:

from fastapi import HTTPException, Request
from fastapi.responses import HTMLResponse

@app.exception_handler(HTTPException)
async def custom_http_exception_handler(request: Request, exc: HTTPException):
    if exc.status_code == 404:
        return HTMLResponse(
            content="<h1>Access Denied</h1><p>Suspicious activity detected.</p>",
            status_code=404
        )
    return JSONResponse(
        status_code=exc.status_code,
        content={"detail": exc.detail}
    )

Reusing Across Multiple Endpoints

Initialize once, use everywhere:

app = FastAPI()
roundtable = Roundtable(max_risk_score=60)

@app.post("/contact", dependencies=[Depends(roundtable(form_field="rt_session_id"))])
async def contact(): ...

@app.post("/signup", dependencies=[Depends(roundtable(form_field="rt_session_id"))])
async def signup(): ...

@app.post("/api/data", dependencies=[Depends(roundtable(http_header="X-Session-ID"))])
async def api_data(): ...

Configuration

Environment Variables

Store your API key securely:

export ROUNDTABLE_API_KEY="your_secret_key"

Then initialize without explicit key:

roundtable = Roundtable()  # Reads from environment

Parameters

Parameter Type Default Description
api_key str | None None Roundtable API secret key. If not provided, reads from ROUNDTABLE_API_KEY environment variable.
status_code int 404 HTTP status code to raise when validation fails. Using 404 makes bot detection less obvious.
max_risk_score int 50 Maximum acceptable risk score (0-100). Sessions with higher scores are rejected.

Risk Score Guidelines

Risk scores range from 0 (definitely human) to 100 (definitely bot):

  • 0-30: Very likely human - safe to allow
  • 30-50: Probably human - acceptable for most use cases
  • 50-70: Uncertain - higher scrutiny recommended
  • 70-100: Very likely bot - should be blocked

Recommended thresholds:

  • Lenient (max_risk_score=70): Allow most traffic, block obvious bots
  • Balanced (max_risk_score=50): Default setting, good for most applications
  • Strict (max_risk_score=30): High security, may have false positives

Adjust based on your needs. Start with 50 and tune based on your traffic patterns.

Use Cases

Contact Form Spam Prevention

@app.post("/contact", dependencies=[Depends(roundtable(form_field="rt_session_id"))])

Block automated spam submissions while keeping forms simple for real users.

Account Signup Protection

@app.post("/signup", dependencies=[Depends(roundtable(form_field="rt_session_id"))])

Prevent bot-driven account creation and fake registrations.

API Rate Limit Bypass Prevention

@app.post("/api/resource", dependencies=[Depends(roundtable(http_header="X-Session-ID"))])

Stop bots from bypassing rate limits with multiple IPs or identities.

Comment/Review Spam Blocking

@app.post("/reviews", dependencies=[Depends(roundtable(form_field="rt_session_id"))])

Keep your user-generated content authentic and spam-free.

Credential Stuffing Prevention

@app.post("/login", dependencies=[Depends(roundtable(form_field="rt_session_id"))])

Protect login endpoints from automated credential testing attacks.

API Reference

Roundtable

A reusable session validator for FastAPI applications.

class Roundtable:
    def __init__(
        self,
        *,
        api_key: str | None = None,
        status_code: int = 404,
        max_risk_score: int = 50
    ) -> None:
        """Initialize a session validator with Roundtable.ai API credentials."""

__call__(*, form_field: str | None = None, http_header: str | None = None, body_field: str | None = None)

Creates a FastAPI dependency for session validation. Exactly one parameter must be provided.

Returns: An async dependency function compatible with Depends()

Example:

# Validate from form field
Depends(roundtable(form_field="rt_session_id"))

# Validate from HTTP header
Depends(roundtable(http_header="X-Session-ID"))

# Validate from request body field
Depends(roundtable(body_field="sessionId"))

async validate_session(session_id: str) -> None

Validates a session ID against the Roundtable.ai API. Raises HTTPException if validation fails.

For advanced usage and full API documentation, see the source code.

Requirements

  • Python 3.9 or higher
  • fastapi
  • aiohttp
  • pydantic

Links

Disclaimer

This library is maintained independently and is not an official Roundtable.ai product. While the author is employed by Roundtable.ai, this project is a community contribution and not affiliated with or endorsed by the company.

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request or open an Issue on GitHub.

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

fastapi_roundtable-0.1.0.tar.gz (7.6 kB view details)

Uploaded Source

Built Distribution

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

fastapi_roundtable-0.1.0-py3-none-any.whl (8.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: fastapi_roundtable-0.1.0.tar.gz
  • Upload date:
  • Size: 7.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.2 CPython/3.13.2 Darwin/24.6.0

File hashes

Hashes for fastapi_roundtable-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8656ab21bc2bd0a158dbad3f7f58588dd883b79976b0d290f419fad85a23f048
MD5 4eb1a87ee723742494ba64a071e66161
BLAKE2b-256 f3a34cc6ada02e507d05d1ff989fcb4eec8766e0e629577f9e00d6296c3f323e

See more details on using hashes here.

File details

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

File metadata

  • Download URL: fastapi_roundtable-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.2 CPython/3.13.2 Darwin/24.6.0

File hashes

Hashes for fastapi_roundtable-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 efaa474ffc8f18a35b60727a4f7e435f6b025b558c494dfc6e9e0b4c7b82941c
MD5 65836d578fbaa592322a0fe3780dd3f8
BLAKE2b-256 072794c4eb67472e6fc086b180ec797363346325ae8207543304a4c2337e896c

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