Docs
The agent
A small collector that runs beside n8n, reads it read-only, and pushes signed metadata outbound. Includes how to tell whether it is working.
The agent is a standalone container you run next to your n8n. It reads n8n read-only, reduces each execution to metadata on your host, and pushes that to Obsevo over outbound HTTPS. It never opens a port to the internet and never receives a callback, so it works from inside a private network with no inbound firewall rule.
You need the three values from connecting an instance: the instance ID, the one-time secret, and your ingest URL.
Choose a read mode
The agent can read n8n through its REST API or straight from its database.
API mode (recommended)
Needs an n8n API key. This is the mode to use: it reports per-node output counts, which is what green-but-broken detection compares against.
docker run -d --name obsevo-agent --restart unless-stopped \
-e OBSEVO_INGEST_URL=https://ingest.example.com/ingest \
-e OBSEVO_INSTANCE_ID=<uuid> \
-e OBSEVO_INGEST_SECRET=<secret> \
-e OBSEVO_N8N_MODE=api \
-e OBSEVO_N8N_URL=http://n8n:5678 \
-e OBSEVO_N8N_API_KEY=<n8n api key> \
-v obsevo-agent-data:/data -e OBSEVO_CURSOR_FILE=/data/cursor \
ghcr.io/obsevo/obsevo-agent:latestA read-only n8n key is enough. The agent never writes through it — control actions are a separate, opt-in path that does not go through the agent at all.
DB mode
For installs where an API key is not practical. Use a SELECT-only role:
CREATE USER obsevo_ro WITH PASSWORD '…';
GRANT CONNECT ON DATABASE n8n TO obsevo_ro;
GRANT USAGE ON SCHEMA public TO obsevo_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO obsevo_ro;Then set OBSEVO_N8N_MODE=db and OBSEVO_N8N_DB_URL instead of the two API
variables.
Verify it's working
This is where setups quietly fail, so check it rather than assuming.
Expect the first runs within one poll interval — 30 seconds by default. The agent only reports executions that finish after it starts, so if the workflow runs hourly, nothing will appear until it next runs. Trigger a workflow manually if you want an immediate answer.
Check the agent's own logs first:
docker logs obsevo-agent --tail 50Then confirm the credentials are accepted, without waiting for a run:
curl -H 'authorization: Bearer <event key>' https://ingest.example.com/ingest/verifyA 200 with your instance name means the key and the URL are both right.
When nothing arrives
| Symptom | Cause | Fix |
|---|---|---|
401 invalid signature | The secret does not match the instance | Rotate the secret on the instance and restart the agent |
401 stale or invalid timestamp | Host clock drift beyond ±5 minutes | Fix NTP on the agent host — the signature covers the timestamp |
401 unknown instance | Wrong instance ID, or it was deleted | Re-check the ID against the dashboard |
| Connection refused or DNS failure | Wrong ingest URL, or ingest.<domain> has no DNS record | Confirm the hostname resolves from the agent host |
| Agent logs look clean, dashboard shows nothing | n8n has had no executions since the agent started | Run a workflow manually |
403 or empty results from n8n in API mode | The n8n API key lacks read access | Issue a key with read scope |
| Instance shows as down after working | The agent stopped, or the host lost outbound access | docker ps, then check egress |
All options
| Env var | Default | Notes |
|---|---|---|
OBSEVO_INGEST_URL | — | required |
OBSEVO_INSTANCE_ID | — | required (uuid) |
OBSEVO_INGEST_SECRET | — | required |
OBSEVO_N8N_MODE | — | api or db |
OBSEVO_N8N_URL / OBSEVO_N8N_API_KEY | — | API mode |
OBSEVO_N8N_DB_URL | — | DB mode |
OBSEVO_POLL_INTERVAL_MS | 30000 | poll cadence — see below |
OBSEVO_SNAPSHOT_EVERY | 10 | workflow snapshot every N cycles |
OBSEVO_MAX_BATCH | 200 | executions per cycle (max 500) |
OBSEVO_CURSOR_FILE | .obsevo-agent-cursor | persist it, for incremental resume |
OBSEVO_AGENT_VERSION | 0.0.0 | reported in heartbeats |
OBSEVO_POLL_INTERVAL_MS trades n8n API load against freshness. With
real-time capture on, the poll only backfills what the
hook missed. Without it — on n8n Cloud, for instance — the interval is how far
behind n8n Obsevo runs, and missed-run and SLA timing inherit the same lag. Each
cycle is a single "executions since cursor" request, so raise it only if n8n is
struggling.
And for real-time capture, which is off unless a token is set:
| Env var | Default | Notes |
|---|---|---|
OBSEVO_HOOK_TOKEN | — | Setting it enables the hook receiver. Minimum 16 characters |
OBSEVO_HOOK_HOST | 127.0.0.1 | Bind address. Keep it off the public internet |
OBSEVO_HOOK_PORT | 5680 | Port the receiver listens on |
OBSEVO_HOOK_MAX_BYTES | 16777216 | Largest accepted hook body |
And for node data capture, which is off until an admin enables it in the dashboard:
| Env var | Default | Notes |
|---|---|---|
OBSEVO_PAYLOAD_CAPTURE | on | off refuses capture on this host, whatever the dashboard says |
Mount a volume for OBSEVO_CURSOR_FILE. Without it, a restarted agent has no
memory of where it got to.
What actually leaves your host
Per node: status, timing, item counts, and error text. For AI nodes: the model name, the provider, token counts, and a whitelisted set of scalar tuning parameters.
Never by default: execution payloads, prompt or completion content, credentials, or arbitrary node parameters. Full detail is on the security page.
The one exception is node data capture, which an admin
can switch on per instance or per workflow to store node inputs and outputs for
chosen run outcomes. Credentials and file contents are removed on the agent even
then, and OBSEVO_PAYLOAD_CAPTURE=off lets you refuse it on your side.