Documentation
Platform Integration/Python Integration

Python Integration

Spyglasses integrates seamlessly with Python web applications through our official Python SDK. The SDK provides middleware that works with Django, Flask, FastAPI, and any other WSGI/ASGI-based Python framework.

Installation

  1. Install the Python package:

    pip install spyglasses

    Or with framework-specific dependencies:

    # For Django projects
    pip install 'spyglasses[django]'
     
    # For Flask projects  
    pip install 'spyglasses[flask]'
     
    # For FastAPI projects
    pip install 'spyglasses[fastapi]'
  2. Set your API key: Add your Spyglasses API key to your environment variables:

    SPYGLASSES_API_KEY=your_api_key_here
    

Django Integration

Add the middleware to your Django application in settings.py:

# settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'spyglasses.middleware.DjangoMiddleware',  # Add here
    'django.contrib.sessions.middleware.SessionMiddleware',
    # ... your other middleware
]
 
# Optional: Configure Spyglasses settings
SPYGLASSES_API_KEY = os.getenv('SPYGLASSES_API_KEY')
SPYGLASSES_DEBUG = True  # Enable debug logging

Option 2: Advanced Configuration

Create a configuration for more control:

# settings.py
import os
 
# Spyglasses Configuration
SPYGLASSES_API_KEY = os.getenv('SPYGLASSES_API_KEY')
SPYGLASSES_DEBUG = DEBUG  # Use Django's DEBUG setting
SPYGLASSES_PLATFORM_TYPE = 'django'
SPYGLASSES_EXCLUDE_PATHS = [
    '/admin/',               # Exclude Django admin
    '/static/',              # Exclude static files
    '/media/',               # Exclude media files
    '/api/internal/',        # Exclude internal API routes
]
 
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'spyglasses.middleware.DjangoMiddleware',
    # ... other middleware
]

Programmatic Configuration

For more advanced setups, configure programmatically:

# apps.py or __init__.py
from django.apps import AppConfig
from spyglasses import configure, Configuration
 
class MyAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'myapp'
    
    def ready(self):
        configure(Configuration(
            api_key=os.getenv('SPYGLASSES_API_KEY'),
            debug=settings.DEBUG,
            platform_type='django',
            exclude_paths=['/admin/', '/api/internal/']
        ))

Django-Specific Considerations

Static Files: Django static files (/static/, /media/) are automatically excluded from monitoring.

Admin Interface: Django admin routes (/admin/) are automatically excluded by default.

API Applications: For Django REST Framework or API-only applications:

# settings.py
REST_FRAMEWORK = {
    # Your DRF settings
}
 
# Spyglasses works normally with DRF
MIDDLEWARE = [
    'spyglasses.middleware.DjangoMiddleware',
    # ... other middleware including DRF
]

Development vs Production: Consider different settings per environment:

# settings.py
if DEBUG:
    SPYGLASSES_DEBUG = True
    SPYGLASSES_EXCLUDE_PATHS = ['/debug-toolbar/']
else:
    SPYGLASSES_DEBUG = False
    SPYGLASSES_AUTO_SYNC = True

Flask Integration

Basic Flask Setup

# app.py
from flask import Flask
from spyglasses.middleware import FlaskMiddleware
 
app = Flask(__name__)
 
# Initialize Spyglasses middleware
middleware = FlaskMiddleware(
    app=app,
    api_key=os.getenv('SPYGLASSES_API_KEY'),
    debug=app.debug,
    platform_type='flask'
)
 
@app.route('/')
def hello():
    return 'Hello World!'

Flask with Configuration

# app.py
from flask import Flask
from spyglasses import Configuration
from spyglasses.middleware import FlaskMiddleware
 
app = Flask(__name__)
 
# Create Spyglasses configuration
config = Configuration(
    api_key=os.getenv('SPYGLASSES_API_KEY'),
    debug=app.debug,
    platform_type='flask',
    exclude_paths=['/health', '/metrics']
)
 
# Initialize middleware with configuration
middleware = FlaskMiddleware(app=app, configuration=config)

Route-Specific Protection

Use the decorator for protecting specific routes:

from spyglasses.middleware.flask import spyglasses_middleware
 
@app.route('/api/sensitive')
@spyglasses_middleware(api_key=os.getenv('SPYGLASSES_API_KEY'))
def sensitive_data():
    return {'data': 'sensitive information'}

Flask Blueprints

Spyglasses works automatically with Flask blueprints:

# blueprints.py
from flask import Blueprint
 
api = Blueprint('api', __name__, url_prefix='/api')
 
@api.route('/data')
def get_data():
    return {'data': 'protected by Spyglasses'}
 
# Register blueprint
app.register_blueprint(api)

FastAPI Integration

Basic FastAPI Setup

# main.py
from fastapi import FastAPI
from spyglasses.middleware import FastAPIMiddleware
 
app = FastAPI()
 
# Add Spyglasses middleware
app.add_middleware(
    FastAPIMiddleware,
    api_key=os.getenv('SPYGLASSES_API_KEY'),
    debug=True,
    platform_type='fastapi'
)
 
@app.get("/")
async def root():
    return {"message": "Hello World"}

FastAPI with Advanced Configuration

# main.py
from fastapi import FastAPI
from spyglasses import Configuration
from spyglasses.middleware import FastAPIMiddleware
 
app = FastAPI()
 
# Create configuration
config = Configuration(
    api_key=os.getenv('SPYGLASSES_API_KEY'),
    debug=True,
    platform_type='fastapi',
    exclude_paths=['/docs', '/redoc', '/openapi.json']
)
 
# Add middleware with configuration
app.add_middleware(FastAPIMiddleware, configuration=config)

Convenience Setup Function

# main.py
from fastapi import FastAPI
from spyglasses.middleware.fastapi import setup_spyglasses
 
app = FastAPI()
 
# Easy setup with all defaults
setup_spyglasses(
    app,
    api_key=os.getenv('SPYGLASSES_API_KEY'),
    debug=True
)

Other Python Frameworks

Starlette

# app.py
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from spyglasses.middleware import ASGIMiddleware
 
async def homepage(request):
    return JSONResponse({'hello': 'world'})
 
app = Starlette(routes=[
    Route('/', homepage),
])
 
# Wrap with Spyglasses
app = ASGIMiddleware(
    app,
    api_key=os.getenv('SPYGLASSES_API_KEY'),
    platform_type='starlette'
)

Tornado

# app.py
import tornado.web
from spyglasses.middleware import WSGIMiddleware
 
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
 
app = tornado.web.Application([
    (r"/", MainHandler),
])
 
# For WSGI-compatible setup
from tornado.wsgi import WSGIAdapter
wsgi_app = WSGIAdapter(app)
wsgi_app = WSGIMiddleware(
    wsgi_app,
    api_key=os.getenv('SPYGLASSES_API_KEY')
)

Pyramid

# app.py
from pyramid.config import Configurator
from pyramid.response import Response
from spyglasses.middleware import WSGIMiddleware
 
def hello_world(request):
    return Response('Hello World!')
 
if __name__ == '__main__':
    with Configurator() as config:
        config.add_route('hello', '/')
        config.add_view(hello_world, route_name='hello')
        app = config.make_wsgi_app()
    
    # Wrap with Spyglasses
    app = WSGIMiddleware(
        app,
        api_key=os.getenv('SPYGLASSES_API_KEY'),
        platform_type='pyramid'
    )

Pure WSGI/ASGI

For any WSGI application:

# wsgi_app.py
from spyglasses.middleware import WSGIMiddleware
 
def application(environ, start_response):
    status = '200 OK'
    headers = [('Content-type', 'text/plain')]
    start_response(status, headers)
    return [b'Hello World!']
 
# Wrap with Spyglasses
application = WSGIMiddleware(
    application,
    api_key=os.getenv('SPYGLASSES_API_KEY')
)

For any ASGI application:

# asgi_app.py
from spyglasses.middleware import ASGIMiddleware
 
async def application(scope, receive, send):
    assert scope['type'] == 'http'
    await send({
        'type': 'http.response.start',
        'status': 200,
        'headers': [[b'content-type', b'text/plain']],
    })
    await send({
        'type': 'http.response.body',
        'body': b'Hello World!',
    })
 
# Wrap with Spyglasses
application = ASGIMiddleware(
    application,
    api_key=os.getenv('SPYGLASSES_API_KEY')
)

Configuration Options

All middleware classes accept these configuration options:

middleware = FrameworkMiddleware(
    api_key=os.getenv('SPYGLASSES_API_KEY'),   # Required: Your API key
    debug=False,                               # Enable debug logging
    auto_sync=True,                            # Auto-sync patterns on startup
    platform_type='python',                    # Platform identifier
    cache_ttl=86400,                           # Pattern cache TTL (24 hours)
    exclude_paths=[                            # Paths to exclude
        '/admin/',                             # String matching
        '/api/internal/',                      # Prefix matching
        '/health'                              # Exact matching
    ],
    exclude_extensions=[                       # File extensions to exclude
        '.ico', '.png', '.css', '.js'
    ],
    collect_endpoint='https://...',            # Custom collector endpoint
    patterns_endpoint='https://...'            # Custom patterns endpoint
)

Environment Variables

Configure Spyglasses using environment variables:

VariableDescriptionDefault
SPYGLASSES_API_KEYYour Spyglasses API keyRequired
SPYGLASSES_DEBUGEnable debug loggingfalse
SPYGLASSES_AUTO_SYNCAuto-sync patterns on startuptrue
SPYGLASSES_CACHE_TTLPattern cache TTL in seconds86400 (24 hours)
SPYGLASSES_COLLECT_ENDPOINTCustom collector endpointhttps://www.spyglasses.io/api/collect
SPYGLASSES_PATTERNS_ENDPOINTCustom patterns endpointhttps://www.spyglasses.io/api/patterns
SPYGLASSES_PLATFORM_TYPEPlatform identifierpython

Deployment

Docker

Add environment variables to your Dockerfile:

# Dockerfile
FROM python:3.11-slim
 
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
 
ENV SPYGLASSES_API_KEY=your_api_key_here
ENV SPYGLASSES_DEBUG=false
 
COPY . .
CMD ["python", "app.py"]

Or use docker-compose:

# docker-compose.yml
version: '3.8'
services:
  web:
    build: .
    environment:
      - SPYGLASSES_API_KEY=your_api_key_here
      - SPYGLASSES_DEBUG=false
    ports:
      - "8000:8000"

Heroku

Add your API key to Heroku config vars:

heroku config:set SPYGLASSES_API_KEY=your_api_key_here

AWS Lambda

For serverless applications using frameworks like Chalice or Zappa:

# app.py
import os
from chalice import Chalice
from spyglasses import Client
 
app = Chalice(app_name='myapp')
 
# Initialize Spyglasses client for manual usage
client = Client(api_key=os.getenv('SPYGLASSES_API_KEY'))
 
@app.route('/')
def index():
    # Manual detection in serverless environment
    user_agent = app.current_request.headers.get('user-agent', '')
    result = client.detect(user_agent)
    
    if result.is_bot:
        # Handle bot detection
        pass
    
    return {'hello': 'world'}

Google Cloud Platform

Set environment variables in your app.yaml:

# app.yaml
runtime: python39
 
env_variables:
  SPYGLASSES_API_KEY: "your_api_key_here"
  SPYGLASSES_DEBUG: "false"

Railway

Add environment variables in your Railway dashboard or railway.json:

{
  "$schema": "https://railway.app/railway.schema.json",
  "build": {
    "builder": "NIXPACKS"
  },
  "deploy": {
    "envVars": {
      "SPYGLASSES_API_KEY": "your_api_key_here"
    }
  }
}

Performance Considerations

The Spyglasses Python SDK is optimized for high-performance applications:

  • Minimal Overhead: Typically under 1ms per request
  • Background Logging: API calls run in background threads
  • Smart Exclusions: Static assets automatically excluded
  • Pattern Caching: Compiled regex patterns are cached
  • Thread Safety: All operations are thread-safe

ASGI vs WSGI Performance

  • ASGI (FastAPI, Starlette): Best for async applications
  • WSGI (Django, Flask): Traditional sync applications
  • Both implementations are optimized for their respective paradigms

Async Compatibility

The SDK works seamlessly with async frameworks:

# FastAPI example with async views
from fastapi import FastAPI
from spyglasses.middleware import FastAPIMiddleware
 
app = FastAPI()
app.add_middleware(FastAPIMiddleware, api_key="your-key")
 
@app.get("/")
async def async_endpoint():
    # Spyglasses detection happens automatically
    return {"message": "async response"}

Testing

Disable in Test Environment

# conftest.py (pytest) or test_settings.py (Django)
import os
 
# Disable Spyglasses in tests
os.environ['SPYGLASSES_API_KEY'] = ''
os.environ['SPYGLASSES_AUTO_SYNC'] = 'false'

Mock API Calls

For integration tests, mock the API endpoints:

# test_spyglasses.py
import pytest
from unittest.mock import patch
from spyglasses import Client
 
class TestSpyglasses:
    @patch('spyglasses.client.requests.get')
    @patch('spyglasses.client.requests.post')
    def test_bot_detection(self, mock_post, mock_get):
        # Mock API responses
        mock_get.return_value.status_code = 200
        mock_get.return_value.json.return_value = {
            'patterns': [],
            'ai_referrers': [],
            'version': '1.0.0'
        }
        
        client = Client(api_key='test-key')
        result = client.detect('GPTBot/1.0')
        
        assert result.is_bot

Django Test Setup

# test_settings.py
from .settings import *
 
# Disable Spyglasses for tests
SPYGLASSES_API_KEY = None
SPYGLASSES_AUTO_SYNC = False
 
# Remove middleware for faster tests
MIDDLEWARE = [m for m in MIDDLEWARE if 'spyglasses' not in m.lower()]

pytest Configuration

# conftest.py
import pytest
from spyglasses import reset_configuration
 
@pytest.fixture(autouse=True)
def reset_spyglasses():
    """Reset Spyglasses configuration before each test."""
    reset_configuration()
    yield
    reset_configuration()

Manual Usage

You can use Spyglasses without middleware for custom implementations:

from spyglasses import Client, Configuration
 
# Initialize client
config = Configuration(api_key='your-api-key')
client = Client(config)
 
# Detect bots
user_agent = 'Mozilla/5.0 (compatible; ChatGPT-User/1.0)'
result = client.detect_bot(user_agent)
 
if result.is_bot:
    print(f"Bot detected: {result.info.company}")
    print(f"Should block: {result.should_block}")
 
# Detect AI referrers
referrer = 'https://chat.openai.com/'
result = client.detect_ai_referrer(referrer)
 
if result.source_type == 'ai_referrer':
    print(f"AI referrer: {result.info.name}")
 
# Combined detection
result = client.detect(user_agent, referrer)
 
# Manual logging
request_info = {
    'url': 'https://example.com/api',
    'user_agent': user_agent,
    'ip_address': '192.168.1.1',
    'request_method': 'GET',
    'request_path': '/api',
    'request_query': 'param=value',
    'referrer': referrer,
    'response_status': 200,
    'response_time_ms': 150,
    'headers': {'Host': 'example.com'}
}
 
client.log_request(result, request_info)

Verifying Installation

After deploying your Python application with Spyglasses:

  1. Check logs for Spyglasses initialization (if debug enabled)
  2. Test with curl to generate bot traffic:
    curl -H "User-Agent: GPTBot/1.0" https://yoursite.com/
  3. Monitor your dashboard at spyglasses.io for incoming data
  4. Enable debug temporarily to see detection in action:
    os.environ['SPYGLASSES_DEBUG'] = 'true'

Troubleshooting

Common Issues

Package not found

  • Ensure you've installed with pip install spyglasses
  • Check virtual environment activation
  • Verify Python version compatibility (3.8+)

API key not found

  • Verify SPYGLASSES_API_KEY environment variable is set
  • Check for typos in environment variable name
  • Ensure deployment includes environment variables

Middleware not working

  • Verify middleware is added to your framework correctly
  • Check middleware order (should be early in the stack)
  • Enable debug mode to see processing logs

Import errors

  • Install framework-specific extras: pip install 'spyglasses[django]'
  • Check for conflicting package versions
  • Ensure all dependencies are installed

Performance issues

  • Review exclude_paths for overly broad patterns
  • Monitor background thread performance
  • Check network latency to Spyglasses endpoints

Debug Mode

Enable debug logging to troubleshoot:

import os
os.environ['SPYGLASSES_DEBUG'] = 'true'
 
# Or programmatically
from spyglasses import configure, Configuration
configure(Configuration(debug=True))

Debug output includes:

  • Pattern loading and synchronization
  • Request processing and detection results
  • API communication and responses
  • Performance timing information

Framework-Specific Issues

Django

  • Ensure middleware is in correct position in MIDDLEWARE list
  • Check for conflicts with authentication middleware
  • Verify Django version compatibility (3.2+ recommended)

Flask

  • Confirm Flask version compatibility (2.0+ recommended)
  • Check for blueprint registration order
  • Verify WSGI server configuration

FastAPI

  • Ensure FastAPI version compatibility (0.68+ recommended)
  • Check middleware order with other ASGI middleware
  • Verify async/await usage is correct

Memory and Threading

Monitor resource usage:

  • Check thread count for background logging
  • Monitor memory usage with pattern caching
  • Adjust cache_ttl if patterns update frequently

Need help? Contact support@spyglasses.io