Frequently asked questions about ObservaKit.
Data observability is knowing the health of your data at all times, without manually querying tables or waiting for dasheholders to file bug reports. The five classic pillars are: Freshness, Volume, Quality, Schema, and Lineage. ObservaKit adds Distribution Drift and Data Contracts on top of these.
Great Expectations is a quality-check library. You write tests, run them, and get pass/fail. ObservaKit is a full observability layer built on top of that: it stores history, detects anomalies over time, monitors freshness and schema separately, integrates with your orchestrator, and routes alerts to the right channel. Think of GX as a linter and ObservaKit as the full CI pipeline.
Monte Carlo and Metaplane are excellent SaaS products that cost $30k–$100k/year. They're the right choice for large enterprise teams. ObservaKit is for 1–5 person data teams at startups who need the same capabilities without the sales process or the budget. You self-host it, you own your data, and it's free forever.
No. ObservaKit runs entirely in your environment. The only external HTTP calls are to your configured alert channels (Slack, Discord, etc.). Nothing is sent to WillowVibe or any third party.
ObservaKit runs scheduled SELECT COUNT(*), SELECT MAX(timestamp), and information_schema queries. These are read-only and lightweight. For freshness and volume checks on indexed timestamp columns, a typical query takes < 1 second even on multi-billion-row tables. Distribution snapshots on large tables are the most expensive — throttle the schedule or use table sampling if needed.
Yes. Run the FastAPI backend directly:
pip install -e .
uvicorn backend.main:app --host 0.0.0.0 --port 8000You'll need a PostgreSQL database for the metadata store (or use SQLite for single-node dev: set METADATA_DB_TYPE=sqlite).
Yes, for development or single-node setups:
METADATA_DB_TYPE=sqliteSQLite is not recommended for production because it doesn't handle concurrent writes well (e.g. the scheduler and an incoming webhook firing simultaneously).
Currently ObservaKit monitors one warehouse per instance. To monitor two separate databases, run two instances with different WAREHOUSE_* env vars and different metadata DB names. Multi-warehouse support within a single instance is on the roadmap.
Yes. Everything in config/kit.yml:
freshness:
schedule_minutes: 15 # default: 15 min
volume:
schedule_minutes: 60 # default: 60 min
schema_drift:
schedule_minutes: 360 # default: every 6 hours
distribution:
schedule_minutes: 360 # default: every 6 hours- Copy
connectors/postgres.pyas a starting point. - Implement the
WarehouseConnectorabstract class (6 methods). - Register it in
connectors/base.py'sget_warehouse_connector()factory. - Open a PR — we'd love to include it in the official release!
Volume tracks total row counts over time using statistical anomaly detection. It answers: "Is there roughly the right amount of data?" It doesn't look at values at all.
Quality checks look at the actual data: are there nulls? Duplicate PKs? Out-of-range values? They answer: "Is the data correct?"
Both are necessary. A volume anomaly can tell you a pipeline broke. Quality checks tell you the data that arrived is wrong.
- Use Quality Checks for hard rules that should always be true: "order_id must never be null", "amount must be >= 0".
- Use Distribution Drift for soft signals where the historical norm is your reference: "the distribution of
statusvalues shouldn't change dramatically between runs".
Quality checks are deterministic. Distribution drift is statistical and requires historical data before it becomes meaningful (typically 2+ snapshots).
A data contract is a formal YAML file that documents and enforces what a table should look like. Use it when:
- Multiple teams (or services) produce data that analytics/ML depends on.
- You want a single source of truth for "what does this table promise to contain?"
- You're doing a data migration and need to verify the destination matches the source spec.
ObservaKit watches your dbt project directory for target/run_results.json. After each dbt run or dbt test, it reads the file and stores:
- Each model run as a
PipelineRunrecord (with duration and status) - Each test result as a
CheckResultrecord
No dbt package installation, no changes to your dbt project, no dbt Cloud required.
Use routing rules in kit.yml:
alerts:
routing:
- match:
alert_type: "schema"
table_pattern: "payments.*"
channel: slack
slack_channel: "#finance-data-alerts"
- match:
alert_type: "freshness"
channel: slack
slack_channel: "#data-freshness"
- match:
alert_type: "contract"
channel: discordUse suppressions:
# Via API
curl -X POST http://localhost:8000/suppress \
-H "X-API-Key: $OBSERVAKIT_API_KEY" \
-d '{"table_name": "public.orders", "suppress_hours": 4}'
# Via CLI
observakit suppress orders 4h
# Via kit.yml (permanently disable a specific check)
# Set alert: null for that tableYes. ObservaKit supports Native PagerDuty integration using the Events API v2. You only need to provide your PAGERDUTY_ROUTING_KEY in .env and route alerts accordingly:
alerts:
routing:
- match:
alert_type: "quality"
channel: pagerdutyThis feature was delivered early due to high demand. Native integration ensures better event deduplication and incident management compared to generic webhooks.
All API endpoints (except /healthz, /metrics, and /) require an X-API-Key header. Set OBSERVAKIT_API_KEY in your .env. Use a strong random string (e.g. openssl rand -hex 32).
CORS is configurable via CORS_ORIGINS. For production, set it to only your dashboard domain.
The backend itself doesn't write to your warehouse — it only writes to its own metadata DB. The warehouse connection only needs SELECT on your target tables and SELECT on information_schema.
No. Run it inside your VPC/private network and access it via a VPN or internal load balancer. The API key provides authentication but not encryption — always use TLS in front of it (e.g. an nginx proxy with a certificate).
git pull origin main
docker compose build backend
docker compose up -d backend
# Alembic migrations run automatically on startupThe metadata store is a PostgreSQL database. Back it up like any other Postgres DB:
docker compose exec postgres pg_dump -U observakit observakit > backup_$(date +%Y%m%d).sqldocker compose down -v # removes volumes including the metadata DB
docker compose up -d
make demo # optionally reload mock dataConnect to the metadata DB and delete old records:
-- Delete check results older than 90 days
DELETE FROM check_results WHERE executed_at < NOW() - INTERVAL '90 days';
DELETE FROM volume_records WHERE recorded_at < NOW() - INTERVAL '90 days';
DELETE FROM freshness_records WHERE checked_at < NOW() - INTERVAL '90 days';
DELETE FROM alert_logs WHERE sent_at < NOW() - INTERVAL '90 days';
-- etc.Yes! Run observakit init after cloning the repo. This interactive wizard will detect your warehouse type, help you set up your .env file, and verify your connection immediately.