ReplayStack Python SDK for backend event capture, exception tracing, and replay debugging.
Project description
ReplayStack Python SDK
ReplayStack's Python SDK captures backend API events, exceptions, stack traces, breadcrumbs, and custom events, then ships them to the ReplayStack ingestion API. It's a feature-aligned port of the official @replaystack/sdk for Node.js.
It supports:
- Manual and middleware-driven event capture
- Manual exception capture with parsed stack frames
- Breadcrumb buffer with request-scoped context
- Sensitive data masking (matches the TS default mask list)
- Configurable timeouts, retries, sampling, and payload truncation
- Offline queue + manual
flush()/close()lifecycle - Periodic background flush
- Auto-detection of the request's
Authorizationmode (bearer/basic/api_key/cookie/other/none) before masking - Process guards for unhandled exceptions + graceful shutdown flushing
- FastAPI / Starlette, Flask, and Django integrations with middleware options matching TS Express options
- Queue jobs, cron jobs, background workers, and custom events
Default ingestion URL:
https://api.replaystack.co/api/v1/ingest/events
SDK headers sent on every request:
x-tracereplay-api-key: rs_live_xxxxxxxxx
x-replaystack-api-key: rs_live_xxxxxxxxx
x-replaystack-sdk: python
x-replaystack-sdk-version: 1.0.0
x-tracereplay-api-key is the canonical header for the TraceReplay backend; x-replaystack-api-key is kept as a duplicate alias so older receivers keep working.
Installation
pip install replaystack-sdk
For framework extras:
pip install replaystack-sdk[fastapi]
pip install replaystack-sdk[flask]
pip install replaystack-sdk[django]
pip install replaystack-sdk[all]
Environment Variables
The SDK reads the same variables the TS SDK does:
REPLAYSTACK_API_KEY=rs_live_xxxxxxxxxxxxxxxxx
REPLAYSTACK_ENDPOINT=https://api.replaystack.co
REPLAYSTACK_INGEST_URL=https://api.replaystack.co/api/v1/ingest/events
REPLAYSTACK_SERVICE_NAME=order-service
REPLAYSTACK_ENVIRONMENT=production
REPLAYSTACK_APP_VERSION=1.0.0
REPLAYSTACK_COMMIT_HASH=a7f91c
# Runtime tuning
REPLAYSTACK_ENABLED=true
REPLAYSTACK_TIMEOUT_MS=2500
REPLAYSTACK_RETRIES=1
REPLAYSTACK_SAMPLE_RATE=1.0
REPLAYSTACK_CAPTURE_SUCCESS=true
REPLAYSTACK_MAX_PAYLOAD_SIZE_BYTES=524288
REPLAYSTACK_MAX_BREADCRUMBS=50
REPLAYSTACK_OFFLINE_QUEUE_MAX=100
REPLAYSTACK_FLUSH_INTERVAL_MS=0
REPLAYSTACK_COMMIT_HASH identifies the exact deployed code version that generated the event or exception.
Configuration Reference
Every option can be passed as a keyword argument to ReplayStackClient(...). Environment variables (above) act as defaults when the kwarg is omitted.
| Argument | Type | Default | Notes |
|---|---|---|---|
api_key |
str |
REPLAYSTACK_API_KEY env |
Required. Raises ValueError when missing. |
endpoint |
str |
https://api.replaystack.co |
Base URL (no path). |
ingest_url |
str |
<endpoint>/api/v1/ingest/events |
Override the full ingest URL. |
service_name |
str |
env | Service shown in dashboard. |
environment |
str |
env / development |
local / development / staging / production / arbitrary string. |
app_version |
str |
env | Release version (e.g. 1.2.0). |
commit_hash |
str |
env | Git SHA. |
enabled |
bool |
True |
Disable the SDK at runtime without removing code. |
timeout_seconds |
float |
2.5 |
Request timeout per attempt. |
max_retries |
int |
1 |
Retries on network failure (in addition to the first attempt). |
sample_rate |
float |
1.0 |
0.1 = capture 10% of events. |
capture_success |
bool |
True |
When False, only failed/warning events are sent. |
max_payload_bytes |
int |
524288 (512 KB) |
Truncates request/response payloads above this size. |
mask_fields |
Iterable[str] |
[] |
Custom field names to mask (case-insensitive). |
ignored_paths |
Iterable[str] |
[] |
Path prefixes or prefix* globs to skip. |
max_breadcrumbs |
int |
50 |
Per-request breadcrumb cap. |
offline_queue_max |
int |
100 |
Events buffered after the API errors out. Set to 0 to disable. |
flush_interval_seconds |
float |
0 |
When > 0, a daemon thread calls flush() on this interval. |
async_send |
bool |
True |
When True, sends in a background thread. Set False for synchronous workers. |
raise_on_error |
bool |
False |
Re-raise the last transport error after retries (useful in tests). |
on_error |
Callable[[BaseException], None] |
None |
Internal-error hook (e.g. send to logs/metrics). |
on_queue_drop |
Callable[[dict], None] |
None |
Fires when offline queue drops the oldest event. |
transport |
object | requests |
Anything exposing .post(url, json, headers, timeout). Useful for tests. |
Basic Usage
from replaystack_sdk import ReplayStackClient
replaystack = ReplayStackClient(
api_key="rs_live_xxxxxxxxx",
service_name="order-service",
environment="production",
app_version="1.0.0",
commit_hash="a7f91c",
)
replaystack.capture_event(
event_type="custom",
endpoint="daily-report-job",
status="success",
response_payload={"message": "Report generated"},
)
Manual Exception Capture
try:
user = None
user_id = user["id"]
except Exception as exc:
replaystack.capture_exception(
exc,
event_type="custom",
endpoint="process-user",
request_payload={"user": user},
)
raise
The SDK captures:
- error name + error message
- formatted stack trace
- parsed stack frames (
functionName,fileName,lineNumber) - active breadcrumbs
Breadcrumbs
Breadcrumbs are step-by-step debugging hints attached to the next captured event.
replaystack.add_breadcrumb("Order API started")
replaystack.add_breadcrumb("Validating request payload")
replaystack.add_breadcrumb("Calling payment provider", category="payment")
Inside a framework integration each request gets its own breadcrumb scope automatically (via run_with_replaystack_context). Outside a request, breadcrumbs go into the per-client buffer instead — perfect for cron jobs and background workers.
For custom workers, open a scope manually:
from replaystack_sdk import run_with_replaystack_context
with run_with_replaystack_context():
replaystack.add_breadcrumb("worker started")
do_work()
Sampling, captureSuccess, and Ignored Paths
replaystack = ReplayStackClient(
api_key="rs_live_xxx",
sample_rate=0.1, # capture 10% of events probabilistically
capture_success=False, # only ship failed/warning events
ignored_paths=["/health", "/metrics", "/internal/*"],
)
Sampling is purely probabilistic — failed events are not auto-promoted. If you want to always capture failures and 10% of successes, combine capture_success=False with your own filtering, or wrap capture_event yourself.
Sensitive Data Masking
The default mask list matches the TS SDK and includes authorization, password, token, access_token, refresh_token, apikey, api_key, secret, client_secret, cookie, set-cookie, cardNumber, card_number, cvv, otp, and others. Add more via mask_fields.
replaystack = ReplayStackClient(
api_key="rs_live_xxx",
mask_fields=["ssn", "tax_id", "phone_number"],
)
Detection is case-insensitive and treats -, _, and spaces as equivalent.
Authorization headers are inspected before masking so the dashboard can show
the auth mode (e.g. bearer, basic, api_key, cookie) without ever storing
the raw token.
Offline Queue, Flush, and Graceful Shutdown
When the API is unreachable after retries, the prepared payload is buffered in memory (bounded by offline_queue_max). Call flush() or close() to drain it.
replaystack = ReplayStackClient(
api_key="rs_live_xxx",
offline_queue_max=200,
flush_interval_seconds=10, # periodic best-effort drain
on_queue_drop=lambda info: print("dropped", info),
)
# Drain manually (e.g. in a /shutdown handler):
replaystack.flush(timeout_seconds=5)
# Stop the periodic timer and drain one last time:
replaystack.close(timeout_seconds=5)
Process Guards (recommended for long-running servers)
Register interpreter-level hooks so unhandled exceptions are captured and the offline queue is drained when the process exits.
from replaystack_sdk import ReplayStackClient, install_replaystack_process_guards
client = ReplayStackClient(api_key="rs_live_xxx", flush_interval_seconds=10)
unsubscribe = install_replaystack_process_guards(client)
# Later, e.g. in tests:
unsubscribe()
install_replaystack_process_guards wires up:
sys.excepthook→ captures uncaught exceptionssys.unraisablehook→ captures unraisable exceptions (3.8+)- asyncio loop exception handler → captures unhandled task failures
SIGINT,SIGTERM, andatexit→ callclient.flush()before exit
Options:
install_replaystack_process_guards(
client,
uncaught_exception=True,
unraisable_exception=True,
asyncio_unhandled_rejection=True,
flush_on_shutdown=True,
shutdown_signals=[signal.SIGINT, signal.SIGTERM],
)
FastAPI / Starlette
from fastapi import FastAPI
from replaystack_sdk import ReplayStackClient
from replaystack_sdk.integrations.fastapi import FastAPIMiddlewareOptions, setup_fastapi
app = FastAPI()
client = ReplayStackClient(api_key="rs_live_xxx", service_name="fastapi-service")
setup_fastapi(
app,
client,
FastAPIMiddlewareOptions(
capture_request_body=True,
capture_response_body=True,
capture_headers=True,
ignored_paths=["/internal/*"],
get_trace_id=lambda req: req.headers.get("x-request-id"),
should_capture=lambda info: info["statusCode"] != 204,
),
)
@app.post("/orders")
async def create_order(payload: dict):
client.add_breadcrumb("Creating order")
return {"success": True, "order": payload}
The middleware emits an absolute requestUrl, sets x-trace-id on the response, and adds started / finished / exception breadcrumbs automatically. Streaming responses are not body-captured (a marker payload is sent instead).
Flask
from flask import Flask, jsonify, request
from replaystack_sdk import ReplayStackClient
from replaystack_sdk.integrations.flask import FlaskMiddlewareOptions, setup_flask
app = Flask(__name__)
client = ReplayStackClient(api_key="rs_live_xxx", service_name="flask-service")
setup_flask(
app,
client,
FlaskMiddlewareOptions(
capture_request_body=True,
capture_response_body=True,
capture_headers=True,
ignored_paths=["/internal/*"],
get_trace_id=lambda req: req.headers.get("x-request-id"),
should_capture=lambda info: info["statusCode"] != 204,
),
)
@app.post("/orders")
def create_order():
client.add_breadcrumb("Creating order")
return jsonify({"success": True, "order": request.json})
/health, /metrics, and /favicon.ico are ignored by default. The middleware sets x-trace-id on the response.
Django
In settings.py:
from replaystack_sdk import ReplayStackClient
from replaystack_sdk.integrations.django import DjangoMiddlewareOptions
REPLAYSTACK_CLIENT = ReplayStackClient(
api_key="rs_live_xxx",
service_name="django-service",
environment="production",
)
REPLAYSTACK_OPTIONS = DjangoMiddlewareOptions(
capture_request_body=True,
capture_response_body=True,
capture_headers=True,
ignored_paths=["/internal/*"],
get_trace_id=lambda req: req.headers.get("x-request-id"),
should_capture=lambda info: info["statusCode"] != 204,
)
MIDDLEWARE = [
# ... your security/common middleware ...
"replaystack_sdk.integrations.django.ReplayStackDjangoMiddleware",
# ... your custom middleware ...
]
Direct API Contract
POST /api/v1/ingest/events
Content-Type: application/json
x-tracereplay-api-key: rs_live_xxxxxxxxx
x-replaystack-api-key: rs_live_xxxxxxxxx
Example payload:
{
"traceId": "f4b1d4e3-…-…",
"eventType": "api",
"method": "POST",
"endpoint": "/orders",
"requestUrl": "https://api.example.com/orders?ref=email",
"authMode": "bearer",
"authScheme": "Bearer",
"status": "failed",
"statusCode": 500,
"executionTimeMs": 120,
"errorName": "TypeError",
"errorMessage": "'NoneType' object is not subscriptable",
"stackTrace": "Traceback...",
"stackFrames": [
{
"functionName": "create_order",
"fileName": "/app/main.py",
"lineNumber": 18
}
],
"serviceName": "order-service",
"environment": "production",
"appVersion": "1.0.0",
"commitHash": "a7f91c"
}
Production Notes
- The SDK should never crash the user application. Internal errors are silently swallowed unless
raise_on_error=Trueis set. - Failed network calls re-enter the offline queue and drain on the next
flush()/close()/ periodic tick. - Use
ignored_pathsfor/health,/metrics,/favicon.ico(already ignored by integrations) and any other noisy endpoints. - Use
sample_ratefor high-volume successful events; usecapture_success=Falsewhen you only want errors. - Sensitive fields are masked after auth-mode detection, so
authModeis always reliable even when the raw header is masked in the captured payload. - Always call
client.close()(or wire upinstall_replaystack_process_guards) in long-running workers to avoid losing buffered events on shutdown.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file replaystack_sdk-1.1.0.tar.gz.
File metadata
- Download URL: replaystack_sdk-1.1.0.tar.gz
- Upload date:
- Size: 35.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a3869442b06e1303fbc822f6ec6be05bd913e731e40745cba4888815cc590fa
|
|
| MD5 |
5ca29dbed24f4ec9205f5c5ac47a25c2
|
|
| BLAKE2b-256 |
345287f4377f61d14de472c9f50e227e7325b7878db22394a63cab60701f6cd9
|
Provenance
The following attestation bundles were made for replaystack_sdk-1.1.0.tar.gz:
Publisher:
publish.yml on AliJabbar034/replaystack-python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
replaystack_sdk-1.1.0.tar.gz -
Subject digest:
9a3869442b06e1303fbc822f6ec6be05bd913e731e40745cba4888815cc590fa - Sigstore transparency entry: 1523830374
- Sigstore integration time:
-
Permalink:
AliJabbar034/replaystack-python-sdk@923f4dcc3727707df848ad3035bc2f1c9e211ce3 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/AliJabbar034
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@923f4dcc3727707df848ad3035bc2f1c9e211ce3 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file replaystack_sdk-1.1.0-py3-none-any.whl.
File metadata
- Download URL: replaystack_sdk-1.1.0-py3-none-any.whl
- Upload date:
- Size: 29.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c8bf1f1ec2e4f72cd5a200a1d6d3ab23c2f82209c2b214f9c9a3eee902610b53
|
|
| MD5 |
cfe59207423c09f51dae74f0b9dc9155
|
|
| BLAKE2b-256 |
fa672d85ca5d85195ba79658100c7d44b1b80ea3598e8212730ff19129461f88
|
Provenance
The following attestation bundles were made for replaystack_sdk-1.1.0-py3-none-any.whl:
Publisher:
publish.yml on AliJabbar034/replaystack-python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
replaystack_sdk-1.1.0-py3-none-any.whl -
Subject digest:
c8bf1f1ec2e4f72cd5a200a1d6d3ab23c2f82209c2b214f9c9a3eee902610b53 - Sigstore transparency entry: 1523830385
- Sigstore integration time:
-
Permalink:
AliJabbar034/replaystack-python-sdk@923f4dcc3727707df848ad3035bc2f1c9e211ce3 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/AliJabbar034
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@923f4dcc3727707df848ad3035bc2f1c9e211ce3 -
Trigger Event:
workflow_dispatch
-
Statement type: