Configuration Reference¶
Django Orbit is configured through the ORBIT_CONFIG dictionary in your Django settings.
Full Configuration¶
# settings.py
ORBIT_CONFIG = {
# Core Settings
'ENABLED': True,
'AUTH_CHECK': None, # Callable or path to function
'STORAGE_LIMIT': 1000,
# Recording Settings - Phase 1 (Core)
'RECORD_REQUESTS': True,
'RECORD_QUERIES': True,
'RECORD_LOGS': True,
'RECORD_EXCEPTIONS': True,
'RECORD_DUMPS': True,
# Recording Settings - Phase 2 (Extended)
'RECORD_COMMANDS': True,
'RECORD_CACHE': True,
'RECORD_MODELS': True,
'RECORD_HTTP_CLIENT': True,
'RECORD_MAIL': True,
'RECORD_SIGNALS': True,
# Recording Settings - Phase 3 (v0.5.0)
'RECORD_JOBS': True, # Background jobs (Celery, Django-Q, RQ, APScheduler)
'RECORD_REDIS': True, # Redis operations
'RECORD_GATES': True, # Permission/Gate checks
# Recording Settings - Phase 4 (v0.6.0)
'RECORD_TRANSACTIONS': True, # Database transaction blocks
'RECORD_STORAGE': True, # File storage operations
# MCP Server (v0.7.0+)
'MCP_ENABLED': True,
# Storage Backend (v0.8.0+)
'STORAGE_BACKEND': 'orbit.backends.database.DatabaseBackend',
'STORAGE_DB_ALIAS': 'orbit', # only used by DjangoDBBackend
# Query recording (v0.8.1+)
'BULK_CREATE_BATCH_SIZE': None, # set to e.g. 500 to avoid MySQL max_allowed_packet errors
# Resilience
'WATCHER_FAIL_SILENTLY': True, # failed watchers log errors but don't crash
# Performance Settings
'SLOW_QUERY_THRESHOLD_MS': 500,
# Path Filtering
'IGNORE_PATHS': [
'/orbit/',
'/static/',
'/media/',
'/admin/jsi18n/',
'/favicon.ico',
],
# Security Settings
'HIDE_REQUEST_HEADERS': [
'Authorization',
'Cookie',
'X-CSRFToken',
],
'HIDE_REQUEST_BODY_KEYS': [
'password',
'token',
'secret',
'api_key',
'apikey',
'access_token',
'refresh_token',
],
'MAX_BODY_SIZE': 65536,
}
Configuration Options¶
Core Settings¶
ENABLED¶
- Type:
bool - Default:
True - Description: Enable or disable Orbit entirely
STORAGE_LIMIT¶
- Type:
int - Default:
1000 - Description: Maximum number of entries to keep in the database
Orbit automatically cleans up old entries when this limit is exceeded.
AUTH_CHECK¶
- Type:
callableorstr(dotted path to callable) - Default:
None - Description: Function that controls dashboard access. Receives the
requestobject and must returnTrue(allow) orFalse(deny).
# Using a lambda (recommended for simple checks)
ORBIT_CONFIG = {
'AUTH_CHECK': lambda request: request.user.is_staff,
}
# Using a dotted path to a custom function
ORBIT_CONFIG = {
'AUTH_CHECK': 'myapp.auth.can_access_orbit',
}
Recording Settings¶
Core Watchers¶
| Option | Default | Description |
|---|---|---|
RECORD_REQUESTS | True | HTTP request/response cycles |
RECORD_QUERIES | True | SQL queries with N+1 detection |
RECORD_LOGS | True | Python logging output |
RECORD_EXCEPTIONS | True | Unhandled exceptions |
RECORD_DUMPS | True | Debug dumps via orbit.dump() |
Extended Watchers¶
| Option | Default | Description |
|---|---|---|
RECORD_COMMANDS | True | Django management commands |
RECORD_CACHE | True | Cache operations (hits/misses) |
RECORD_MODELS | True | ORM signals (post_save, post_delete) |
RECORD_HTTP_CLIENT | True | Outgoing HTTP requests (httpx, requests) |
RECORD_MAIL | True | Email sending via Django mail |
RECORD_SIGNALS | True | Django signals |
Phase 3 Watchers (v0.5.0+)¶
| Option | Default | Description |
|---|---|---|
RECORD_JOBS | True | Background jobs (Celery, Django-Q, RQ, APScheduler, django-celery-beat) |
RECORD_REDIS | True | Redis operations (GET, SET, DEL, etc.) |
RECORD_GATES | True | Permission/authorization checks |
Phase 4 Watchers (v0.6.0+)¶
| Option | Default | Description |
|---|---|---|
RECORD_TRANSACTIONS | True | Database transaction blocks (atomic()) |
RECORD_STORAGE | True | File storage operations (save, open, delete, exists) |
Performance Settings¶
SLOW_QUERY_THRESHOLD_MS¶
- Type:
int - Default:
500 - Description: Threshold in milliseconds for marking a query as "slow"
Queries exceeding this threshold are highlighted in the dashboard and stats.
Path Filtering¶
IGNORE_PATHS¶
- Type:
list[str] - Default:
['/orbit/', '/static/', '/admin/jsi18n/', '/favicon.ico'] - Description: URL path prefixes to ignore
Always include /orbit/ to avoid infinite loops.
ORBIT_CONFIG = {
'IGNORE_PATHS': [
'/orbit/',
'/static/',
'/media/',
'/health/',
'/metrics/',
'/_internal/',
],
}
Security Settings¶
HIDE_REQUEST_HEADERS¶
- Type:
list[str] - Default:
['Authorization', 'Cookie', 'X-CSRFToken'] - Description: Request headers to mask in logs
Values are replaced with ***HIDDEN***.
HIDE_REQUEST_BODY_KEYS¶
- Type:
list[str] - Default:
['password', 'token', 'secret', 'api_key'] - Description: Request body keys to mask (case-insensitive)
Works recursively on nested objects.
Matching is substring + case-insensitive, so user_password and access_token are masked too.
MASK_KEYS¶
- Type:
list[str] - Default:
['password', 'passwd', 'secret', 'token', 'api_key', 'apikey', 'access_key', 'authorization', 'auth', 'cookie', 'csrf', 'credential', 'private_key', 'client_secret', 'session', 'ssn', 'card_number'] - Description: Terms used for sensitive-data masking. Any payload key containing one of these (case-insensitive) has its value replaced with
***HIDDEN***. This is also the list used to scrub data before it is sent to an AI provider.
MASK_ALL_PAYLOADS¶
- Type:
bool - Default:
False - Description: When
True, every entry's payload is recursively masked at write time (defense in depth across all watchers). Request headers/body are always masked regardless.
TAG_CALLBACK¶
- Type:
callable | str | None - Default:
None - Description: A callable (or dotted import path) receiving an
OrbitEntryand returning a list of tags to attach. Use it to tag entries by tenant, feature or status. Filter by tag with?tag=fooor by typingtag:fooin the dashboard search box. Errors in the callback are swallowed so recording is never affected.
ORBIT_CONFIG = {
'TAG_CALLBACK': lambda entry: (
['5xx'] if entry.type == 'request' and (entry.payload or {}).get('status_code', 0) >= 500 else []
),
}
ENABLE_EXPLAIN¶
- Type:
bool - Default:
True - Description: Allow running
EXPLAINfor a query from its detail panel (on demand).
EXPLAIN_ANALYZE¶
- Type:
bool - Default:
False - Description: Use
EXPLAIN ANALYZE, which executes the statement to gather real timings. Only ever applied to read-onlySELECTs and wrapped in a rolled-back savepoint. Leave off unless you understand the implications.
MAX_BODY_SIZE¶
- Type:
int - Default:
65536(64KB) - Description: Maximum request body size to capture
Environment-Based Configuration¶
# settings/base.py
ORBIT_CONFIG = {
'ENABLED': True,
'STORAGE_LIMIT': 1000,
}
# settings/development.py
ORBIT_CONFIG = {
**ORBIT_CONFIG,
'SLOW_QUERY_THRESHOLD_MS': 100, # Stricter in dev
}
# settings/production.py
ORBIT_CONFIG = {
**ORBIT_CONFIG,
'ENABLED': False, # Disabled in production
}
Resilience¶
WATCHER_FAIL_SILENTLY¶
- Type:
bool - Default:
True - Description: If a watcher raises an exception during recording, log the error and continue instead of propagating it to the host app.
When False, watcher failures will surface as exceptions. Useful during development to catch misconfigured watchers early.
MCP Server (v0.7.0+)¶
MCP_ENABLED¶
- Type:
bool - Default:
True - Description: Enables the MCP server data exposure.
See MCP Server for full setup instructions.
Storage Backend (v0.8.0+)¶
STORAGE_BACKEND¶
- Type:
str(dotted import path) - Default:
"orbit.backends.database.DatabaseBackend" - Description: The backend class used to store all
OrbitEntryrecords.
| Value | Description |
|---|---|
orbit.backends.database.DatabaseBackend | Default — uses Django's default database |
orbit.backends.django_db.DjangoDBBackend | Dedicated Django database alias |
STORAGE_DB_ALIAS¶
- Type:
str - Default:
"orbit" - Description: The database alias used by
DjangoDBBackend. Must match a key inDATABASES. Ignored byDatabaseBackend.
ORBIT_CONFIG = {
"STORAGE_BACKEND": "orbit.backends.django_db.DjangoDBBackend",
"STORAGE_DB_ALIAS": "orbit",
}
See Storage Backends for the full setup guide.
Query Recording (v0.8.1+)¶
BULK_CREATE_BATCH_SIZE¶
- Type:
int | None - Default:
None - Description: Splits the
bulk_createcall used to save SQL query entries into batches of this size.None(default) inserts all entries in a single statement — the original behaviour.
When to use this: If you're on MySQL and a single request triggers a very large number of SQL queries, the default single INSERT can exceed the database's max_allowed_packet limit, causing OperationalError: (2006, 'Server has gone away'). Setting this to 500 (or lower) breaks the insert into smaller chunks.
Note
This setting has no effect on PostgreSQL or SQLite — they do not have a per-packet size limit. It is a MySQL-specific workaround.