Skip to content

ProductAgent

Watch private systems without opening a port.

The open-source agent runs next to your databases and internal services, checks them from inside and dials out with the status. Credentials never leave the host.

  1. Copy the command

    The console fills in the agent key.

  2. Run it next to your services

    A container, a pod, a service unit or a plain binary.

  3. Watch it connect

    The console shows it connected on its first heartbeat.

docker run -d \
  --name observer-agent \
  --hostname "$(hostname)" \
  --restart unless-stopped \
  -v observer-agent-buffer:/data \
  -e AGENT_KEY="${AGENT_KEY}" \
  -e CLOUD_SERVER_URL="https://use.observer" \
  -e BUFFER_PATH="/data/observer-agent-buffer.db" \
  ghcr.io/useobserver/agent:latest
Agent output
[2026-10-06T09:12:01.204Z] [INFO] Debug dashboard listening on http://127.0.0.1:10101[2026-10-06T09:12:01.611Z] [INFO] Successfully fetched metric definitions (1)[2026-10-06T09:12:05.932Z] [INFO] Fetching metric: http metric=3f2a9c1e-5b7d-4e21-9a0c-6d4f8e2b1a73
Waiting for the agent to connect…
The install step from the console's first run. Pick where it runs; the console fills in your agent key.

Boundary

Your credentials stay where they are.

Observer never needs a way into your network, and never holds a password. Observer learns how your systems are doing, never how to log in to them.

On your host

Credentials live in the agent's environment. The agent reads them when a probe runs, and reduces every response, row and series to one number.

observer-agent.env
# observer-agent.env, on the host
ORDERS_DB_URL=postgres://monitor:••••••@10.0.4.12:5432/orders
LEDGER_API_TOKEN=Bearer ••••••••••••

In Observer

The check stores the name of the variable, never its value. A header that looks like a credential is refused in the plain headers field when you save.

source_config
[
  {
    "source_type": "database",
    "source_config": {
      "kind": "postgres",
      "connection_string_ref": "ORDERS_DB_URL",
      "query": "SELECT count(*) FROM jobs WHERE state = 'pending'"
    }
  },
  {
    "source_type": "http",
    "source_config": {
      "url": "https://ledger.internal/healthz",
      "header_refs": { "Authorization": "LEDGER_API_TOKEN" }
    }
  }
]

On the wire

The reading, its status, and a reason code when there was nothing to read. Plus a heartbeat every 30 seconds with the agent's own health, its host name and the names of any custom probes.

outbound, HTTPS, Agent-Key
POST /api/agent/receiver/batch
[
  {
    "metric_id": "8b71d044-2c9e-4f3a-b815-7e0d9c4a6f12",
    "value": 42,
    "timestamp": "2026-10-06T09:14:02.118Z",
    "status": "healthy"
  },
  {
    "metric_id": "e2c47b18-9d3a-4b70-8f25-1c6e4a9b0d37",
    "value": 0,
    "timestamp": "2026-10-06T09:14:05.402Z",
    "status": "no_data",
    "reason": "unexpected_status:503"
  }
]
Heartbeat:versionbuildhostnameuptime_secondsqueue_depthqueue_oldest_age_secondssource_types_activecustom_probes

Direction

Every connection starts on your side.

The agent calls out over HTTPS with its key and refuses redirects, so the key never follows a hop. Nothing in your network listens for Observer.

References

Every secret is a name.

Connection strings, tokens, client certificates, secret headers and gRPC metadata are all set as env var names. If one is missing, the check reports a reason code, never a value.

Opt in

Logs only if you turn them on.

Log broadcast is off by default. Switched on, it streams the agent's own log lines, with Prometheus queries hashed.

On request

CloudWatch names when you browse.

When you browse CloudWatch metrics in the console, the agent lists them with the host's AWS credentials and returns metric names and dimensions. No values.

Changes

Change a check. The agent has it in seconds.

Edit a threshold or add a check in the console, or apply observer.yaml from CI. The agent hears about it on its next check-in, every 30 seconds. No redeploy, no restart.

The agent checks in every 30 seconds. A change saved 12 seconds after one check-in is fetched at the next one, 30 seconds in, and the changed check takes its first reading a few seconds later.
  1. Heartbeat

    Nothing changed. The agent keeps its probes running.

  2. You save a change

    A new threshold, a new check or a different query, in the console or from observer.yaml.

  3. Next heartbeat

    The reply says the definitions changed, so the agent fetches the new set right away.

  4. First reading

    The changed check runs within seconds. Unchanged checks keep their schedule.

Only what changed

Running checks keep their rhythm.

Unchanged checks keep their timers. A changed one restarts and takes its first reading straight away.

Backstop

A full refresh every five minutes.

agent 1.6.0

If a change signal is ever missed, the regular fetch catches it. A freshly started agent polls every 30 seconds until its first checks arrive.

Dashboard

See what it sees, from the host.

By default each agent serves a read-only dashboard on its own machine: each probe's last value and status, the link to Observer, the queue and the recent log.

127.0.0.1:10101

observer-agent

v1.6.0 · pid 1 · bun 1.3.6 · started 76h 12m 09s ago
observer-agent-7c9f5d8…RUNNINGrefresh in 5s

Agent

RuntimeRUNNING
Version
1.6.0
Bun
1.3.6
PID
1
Host
observer-agent-7c9f5d8b6-x2kqp
Memory
48.21 MB
Uptime
76h 12m 09s
Cloud linkCONNECTED
Endpoint
use.observer
Last heartbeat
OK 12s ago
Last push
OK 41s ago
Counterserrors
Probes loaded
6
Evaluations
27,418
Verdicts pushed
1,906
Errors
3
Dropped
0
QueueHEALTHY
Depth
0 / 10000
Oldest
0s
Drain backoff
0 ms
Sources5 active
databaseUP
httpUP
prometheusUP
tls_certUP
grpcUP
PrometheusOK
URL
http://prometheus.monitoring.svc:9090
Last probe
18s ago

Probes · 6 active

ProbeSourceStatusValueThresholdIntervalLast eval
3f2a9c1e
id 3f2a9c1e-5b7d-4e21-9a0c-6d4f8e2b1a73
httphealthy182ok < 500 · bad > 15001m14s ago
8b71d044
id 8b71d044-2c9e-4f3a-b815-7e0d9c4a6f12
databasehealthy42.000ok < 1000 · bad > 50001m33s ago
c09e5a77
id c09e5a77-81d2-4b6c-9e3f-0a5b7d1c8e24
prometheushealthy0.002ok < 0.010 · bad > 0.0501m18s ago
5d3b8e20
id 5d3b8e20-4a6f-4c19-8b2d-9e7f1a3c5d08
tls_certhealthy61.000ok > 30.000 · bad < 7.00060m25m 44s ago
a4e61f93
id a4e61f93-7c2b-4d58-a1e6-3b9f0d2c7e45
grpcdegraded612ok < 300 · bad > 10001m9s ago
e2c47b18
id e2c47b18-9d3a-4b70-8f25-1c6e4a9b0d37
httpno_data—ok < 500 · bad > 15001m27s ago

Log · last 4

09:14:05.402INFOFetching metric: http metric=e2c47b18-9d3a-4b70-8f25-1c6e4a9b0d37
09:14:02.118INFOFetching metric: database metric=8b71d044-2c9e-4f3a-b815-7e0d9c4a6f12
09:13:58.731INFOSuccessfully fetched metric definitions (6)
09:13:51.006INFOFetching metric: grpc metric=a4e61f93-7c2b-4d58-a1e6-3b9f0d2c7e45
NORMALprobes 6healthy 4degraded 1unhealthy 0no_data 1ready 0mem 48.21Mpushes 1906errors 3tick ●
Debug dashboard on port 10101.

Local by default

Bound to the loopback address.

:10101

Exposing it to other machines needs a bearer token; without one the agent stays on 127.0.0.1.

Masked

Settings you can screenshot.

Only agent settings are shown, every value masked, and the dashboard's own token never at all.

Outages

Readings wait out an outage.

When Observer is unreachable, readings queue on disk and go out in order once the link is back. Observer, meanwhile, notices the silent agent and can alert you.

On the host, twenty minutes in

127.0.0.1:10101
Cloud linkDEGRADED
Endpoint
use.observer
Last heartbeat
FAIL 4s ago
HB error
The operation timed out.
Last push
FAIL 2s ago
Push error
The operation timed out.
QueueLAGGING
Depth
18 / 10000
Oldest
20m 7s
Drain backoff
32000 ms

How the queue behaves

Capacity
10,000 rows, adjustable
When full
Oldest rows go first
Retry
1 s, doubling to 5 min
On reconnect
Drains oldest first

Status changes are queued the moment they happen, so the history fills in with the right times once the link is back.

Run it

One small process, wherever your services are.

A container image, a Kubernetes manifest, a systemd unit or a single binary. One agent covers every check on its network.

Platforms

Linux, macOS and Windows.

Standalone binaries for Linux and macOS on x64 and arm64, and Windows on x64, for hosts that cannot pull an image.

Also on the host

A relay for jobs with no way out.

opt in

Cron jobs on a private network can ping the agent, which forwards their heartbeats over its own connection.

Open source

Read every line it runs.

Apache 2.0 on GitHub. Each heartbeat reports the build it came from, so the agents list can tell an official image from a modified one.

Plans

Agents per organization.

Free
1
Starter
3
Pro
10
Business
25
Enterprise
Unlimited

Nothing in your network has to let us in.