Zero-dependency Python SDK for PeekAPI. Built-in middleware for ASGI (FastAPI, Starlette, Litestar), WSGI (Flask, Bottle), and Django.
pip install peekapifrom fastapi import FastAPI
from peekapi import PeekApiClient
from peekapi.middleware import PeekApiASGI
client = PeekApiClient({"api_key": "ak_live_xxx"})
app = FastAPI()
app.add_middleware(PeekApiASGI, client=client)from flask import Flask
from peekapi import PeekApiClient
from peekapi.middleware import PeekApiWSGI
client = PeekApiClient({"api_key": "ak_live_xxx"})
app = Flask(__name__)
app.wsgi_app = PeekApiWSGI(app.wsgi_app, client=client)# settings.py
PEEKAPI = {
"api_key": "ak_live_xxx",
}
MIDDLEWARE = [
"peekapi.middleware.django.PeekApiMiddleware",
# ... other middleware
]from peekapi import PeekApiClient
client = PeekApiClient({"api_key": "ak_live_xxx"})
client.track({
"method": "GET",
"path": "/api/users",
"status_code": 200,
"response_time_ms": 42,
})
# Graceful shutdown (flushes remaining events)
client.shutdown()| Option | Default | Description |
|---|---|---|
api_key |
required | Your PeekAPI key |
endpoint |
PeekAPI cloud | Ingestion endpoint URL |
flush_interval |
10.0 |
Seconds between automatic flushes |
batch_size |
100 |
Events per HTTP POST (triggers flush) |
max_buffer_size |
10000 |
Max events held in memory |
max_storage_bytes |
5242880 |
Max disk fallback file size (5MB) |
max_event_bytes |
65536 |
Per-event size limit (64KB) |
storage_path |
auto | Custom path for JSONL persistence file |
debug |
False |
Enable debug logging |
on_error |
None |
Callback (Exception) -> None for flush errors |
- Middleware intercepts every request/response
- Captures method, path, status code, response time, request/response sizes, consumer ID
- Events are buffered in memory and flushed in batches on a daemon thread
- On network failure: exponential backoff with jitter, up to 5 retries
- After max retries: events are persisted to a JSONL file on disk
- On next startup: persisted events are recovered and re-sent
- On SIGTERM/SIGINT: remaining buffer is flushed or persisted to disk
By default, consumers are identified by:
X-API-Keyheader — stored as-isAuthorizationheader — hashed with SHA-256 (stored ashash_<hex>)
Override with the identify_consumer option to use any header or request property:
client = PeekApiClient({
"api_key": "...",
"identify_consumer": lambda headers: headers.get("x-tenant-id"),
})The callback receives a dict[str, str] of lowercase header names and should return a consumer ID string or None.
- Zero runtime dependencies — uses only Python stdlib
- Background flush — daemon thread with configurable interval and batch size
- Disk persistence — undelivered events saved to JSONL, recovered on restart
- Exponential backoff — with jitter, max 5 consecutive failures before disk fallback
- SSRF protection — private IP blocking, HTTPS enforcement (HTTP only for localhost)
- Input sanitization — path (2048), method (16), consumer_id (256) truncation
- Per-event size limit — strips metadata first, drops if still too large (default 64KB)
- Graceful shutdown — signal handlers (SIGTERM/SIGINT) with disk persistence
- Python >= 3.10
Bug reports and feature requests: peekapi-dev/community
- Fork & clone the repo
- Install dev dependencies —
uv sync --no-install-project - Run tests —
uv run pytest -v - Lint & format —
uv run ruff check src/ tests//uv run ruff format src/ tests/ - Submit a PR
If you find PeekAPI useful, give this repo a star — it helps others discover the project.
Show that your API is monitored by PeekAPI:
[](https://peekapi.dev)MIT