Getting started
Know when your business silently breaks
Standard monitoring tells you when your server crashes. Heron tells you when your business flow quietly fails — when payment webhooks stop firing, email jobs silently stall, or background workers die without throwing an error.
Your system looks healthy. But revenue is stopped. Heron catches that.
Common events people monitor with Heron:
- →
payment.completed— detect payment pipeline failures - →
user.signup— detect broken signup webhooks - →
email.sent— detect stalled email queues - →
job.processed— detect silent worker failures
How it works
Heron works in three phases: ingest, learn, and detect.
When you call heron.track("payment.completed"), Heron records that event with a timestamp. Over time, it computes the average interval between occurrences — for example, payment.completed fires every ~3 minutes.
The background monitor checks each event's last-seen timestamp against its learned interval. If the silence exceeds the expected interval by a meaningful margin, Heron opens an incident and fires a Slack alert. When the event resumes, it automatically closes the incident and reports the total downtime.
Quick start
Get Heron running locally in about 10 minutes.
Clone the repository
git clone https://github.com/pranavkp71/Heron.git
cd heron/heron-serverInstall dependencies
pip install -r requirements.txtSet up PostgreSQL
Create a database, then run the schema. See for the full SQL.
Start the server
python run.pyServer runs at https://heron-production.up.railway.app.
Create a project and get your API key
curl -X POST "https://heron-production.up.railway.app/v1/projects?name=MyApp"# Response
{
"project_id": 1,
"api_key": "heron_xxxxx"
}Track your first event
# In your application code
import sys
sys.path.append("/path/to/heron-sdk")
import heron
heron.init(api_key="heron_xxxxx")
heron.track("payment.completed")Heron will now track this event, learn its frequency, and alert you if it stops.
Database setup
Heron requires a PostgreSQL database with four tables. Run the following SQL after creating your database:
-- Stores your projects and their Slack webhook URLs
CREATE TABLE projects (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
api_key TEXT UNIQUE NOT NULL,
slack_webhook_url TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Raw event log — every heron.track() call lands here
CREATE TABLE events (
id SERIAL PRIMARY KEY,
api_key TEXT,
event_name TEXT,
service TEXT,
environment TEXT,
metadata JSONB,
timestamp BIGINT
);
-- Per-event statistics updated on each track() call
CREATE TABLE event_stats (
api_key TEXT,
event_name TEXT,
service TEXT,
environment TEXT,
last_seen BIGINT,
avg_interval FLOAT,
event_count INTEGER,
incident_active BOOLEAN DEFAULT FALSE
);
-- One row per incident, open or resolved
CREATE TABLE incidents (
id SERIAL PRIMARY KEY,
api_key TEXT,
event_name TEXT,
service TEXT,
environment TEXT,
started_at TIMESTAMP,
resolved_at TIMESTAMP,
duration INTEGER
);Running the server
Start the Heron server from the heron-server directory:
python run.pyThe server starts at https://heron-production.up.railway.app. It runs a background monitor that periodically checks for silent events and opens or resolves incidents.
.env or config file for the database URL setting.Creating a project
Each project gets its own API key. Use separate projects to isolate different apps or environments.
curl -X POST "https://heron-production.up.railway.app/v1/projects?name=MyApp"{
"project_id": 1,
"api_key": "heron_xxxxx"
}Store the api_key securely — it authenticates all SDK calls and API requests for this project.
Slack alerts
Heron sends incident alerts and recovery notifications to a Slack channel via an incoming webhook.
Create a Slack incoming webhook
Go to your Slack workspace → Apps → search for Incoming Webhooks → Add to a channel. Copy the webhook URL.
Add the webhook to your project
curl -X PATCH "https://heron-production.up.railway.app/v1/projects/1/slack" \
-H "Content-Type: application/json" \
-d '{"slack_webhook_url": "https://hooks.slack.com/..."}'Once set, Heron will automatically post alerts when incidents open or resolve.
SDK installation
The Heron SDK is not yet published on PyPI. Install it by pointing Python to the local SDK directory:
import sys
sys.path.append("/path/to/heron-sdk") # absolute path to the cloned repo's SDK folder
import heronpip install heron-sdk. Follow progress on X (@pranavk_p).SDK reference
heron.init()
Call once at application startup to configure the SDK.
heron.init(
api_key="heron_xxxxx", # required
service="payments-service", # optional — tag events by service
environment="production" # optional — "production", "staging", etc.
)| Parameter | Type | Required | Description |
|---|---|---|---|
| api_key | string | required | Your project API key from the create project step. |
| service | string | optional | Tag events with a service name. Useful for multi-service projects. |
| environment | string | optional | Tag events with an environment. Incidents are scoped per environment. |
heron.track()
Call this wherever a business event occurs. Each call records an event occurrence and updates the pattern data.
heron.track(
event_name="payment.completed", # required
metadata={ # optional
"amount": 49.99,
"currency": "USD",
"user_id": "usr_123"
}
)| Parameter | Type | Required | Description |
|---|---|---|---|
| event_name | string | required | Dot-separated event identifier. Use consistent naming — Heron tracks each unique name separately. |
| metadata | dict | optional | Arbitrary key-value data stored with the event. Useful for debugging incidents. Stored as JSONB. |
API reference
All endpoints require your project's api_key as a query parameter.
Alert format
Heron sends two types of Slack messages: incident alerts when an event stops, and recovery alerts when it resumes.
Incident alert
Recovery alert
Pattern learning
Heron does not require you to manually configure thresholds. Instead, it learns the natural cadence of each event from observed data.
On every heron.track() call, Heron computes a rolling average of the interval between consecutive events. This becomes the expected interval for that event. The silence detector runs periodically and compares the current gap (time since last_seen) against the expected interval.
| Situation | Behavior |
|---|---|
| Event is new (< 3 occurrences) | Heron collects data but won't alert yet — not enough history to establish a reliable pattern. |
| Event fires very infrequently | Alerts will fire with a wider tolerance. A once-per-day job won't alert after 5 minutes of silence. |
| Event frequency changes | The rolling average adjusts over time. A sudden permanent change in frequency will stabilize after a few occurrences. |
| Alert fires too aggressively | This may mean your event has high variance (e.g., batch jobs that run irregularly). More sophisticated threshold tuning is on the roadmap. |
Troubleshooting
My event is being tracked but I'm not getting alerts
Heron requires a minimum number of data points before it can establish a reliable pattern. Make sure the event has fired at least 3–5 times. Also confirm your Slack webhook URL is correctly set on your project.
I'm getting false positive alerts
This usually means the event fires at irregular intervals (e.g., user-driven events with low volume, or batch jobs that run at unpredictable times). Heron's pattern learning will stabilize over time as more data is collected.
The SDK is not connecting to the server
Check that your Heron server is running at https://heron-production.up.railway.app and that there are no firewall rules blocking the connection. The SDK fails silently by design — check your server logs to confirm events are being received.
Database connection errors on startup
Make sure your PostgreSQL instance is running and the connection string in your config file is correct. Also confirm all four tables exist by running the setup SQL from the section.
Events show the wrong service or environment
The service and environment values are set globally in heron.init(). If you need different values per event, re-call heron.init() before the relevant heron.track() calls, or open a GitHub issue — per-event overrides may be added.