OTLP metrics push: the zero-agent alternative
The Prometheus /metrics endpoint needs something to reach in: a scraper, a hostname it can hit, a credential in its configuration. OTLP push is the other direction. On every scheduler tick, if a destination is configured and enabled, the engine builds the same canonical backup-health metrics into an OTLP/HTTP JSON body and posts it straight to your collector. Nothing on your side polls for it, and no agent runs anywhere: the engine is the client, your collector’s ingest endpoint is the server, exactly the shape forwarding the audit log to your SIEM (push) describes for the audit trail.
That direction matters for the same structural reason the audit push page gives. The engine dialling out is not an inbound request to your console hostname, so a Cloudflare Access perimeter in front of that hostname never sees it. That is a real advantage over a scrape: the metrics page shows an Access perimeter turning an unattended /metrics scrape away at the edge unless you carve an exemption for it, whereas a push has nothing on that hostname for Access to gate at all. If your collector has no native Prometheus scrape support, or you would rather the engine reach out than expose a scrape target, push is the path that needs neither a scraper nor an Access exemption.
Setting up the destination
A destination is one endpoint, one auth header name and value, and whether it is enabled.
An Owner opens the Metrics push panel
In the console, open the Integrations screen and choose the tile for your metrics vendor (Datadog is the confirmed OTLP-JSON intake). Its panel carries the “Metrics push (OTLP)” controls. They are Owner-gated: a non-owner sees them disabled with the reason, never hidden.
Configure the destination
Supply the collector’s Endpoint URL (
https, screened the same way a webhook or SIEM push destination is: no private or loopback target by default, noworkers.devhost), the Auth header name your vendor expects (most commonlyAuthorization, or a vendor header such as Datadog’sDD-API-KEY), and the write-only auth secret. The secret field always starts blank, even when you are replacing an existing destination: the engine never returns a stored secret, so leaving it blank on a later edit keeps the sealed one unchanged, and only a first-ever create requires it.This set sits in the same high-blast-radius dual-control tier as setting the archive destination itself: once a second Owner exists on the account, saving queues a pending approval rather than repointing the egress immediately, and the console surfaces that as queued for a second owner rather than a false save (the full mechanics are at four-eyes change control).
Or configure it against the API
An Owner can set the same destination directly. This is the route the console calls, so the dual-control gate applies either way:
POST /admin/otlp-push HTTP/1.1 Host: console.example.com Content-Type: application/json { "enabled": true, "endpoint": "https://otlp.example.com/v1/metrics", "authHeaderName": "DD-API-KEY", "authHeaderValue": "<your vendor API key>" }GET /admin/otlp-pushreturns the redacted view (the endpoint, the header name, whether it is enabled, who set it and when, and the delivery trail); the header value never appears in a read.Enable it and wait for the next tick
There is no test-send for this destination, unlike the SIEM push and the generic notify-channel test send: the engine exposes no such route. The first real evidence it works is the delivery trail after the next scheduler tick, so enable it once you are confident in the endpoint and header, and check the trail shortly after.
Watch the delivery trail
The panel shows the most recent 50 attempts (an outcome, an HTTP status where one exists, a coarse reason on failure, and the number of downpipes actually shaped into that push). It never carries a body, a URL beyond what you configured, or the secret.
Clearing the destination is Owner-only and is not dual-control gated, the same asymmetry every egress destination in this product follows: closing a path is the safe direction, so it needs no second approval.
The canonical metric set, as OTLP
The metric names and meanings are identical to the scrape endpoint’s, with one addition. Every metric is an OTLP gauge, rendered as one resourceMetrics entry naming the engine as the resource, one data point per downpipe (or per downpipe-plus-destination for the health series), timestamped to the moment of the push, and carrying the same downpipe_id and downpipe_name labels, with the same rename caveat that applies on the metrics page.
| Metric | Present on /metrics? |
|---|---|
downpipe_backup_last_success_timestamp_seconds |
Yes |
downpipe_backup_success |
Yes |
downpipe_backup_recent_attempts / _recent_successes / _recent_failures |
Yes (the same windowed-gauge caveat applies; see the metrics page) |
downpipe_backup_duration_seconds |
Yes |
downpipe_backup_size_bytes |
Yes |
downpipe_destination_healthy |
Yes |
downpipe_enabled |
No. OTLP push is the only surface that carries this one: 1 for a live downpipe, 0 for one that is paused or decommissioned, so a consumer can gate a staleness alert on enabled == 1 and not page you about a downpipe you deliberately turned off. |
A metric with zero data points this tick (nothing configured has any destination-health state yet, say) is left out of the body entirely, mirroring how a real exporter omits an empty series rather than shipping a metric family with nothing in it. The whole push is capped at 5000 downpipes; past that, the trail records the actual count sent and flags the push as truncated rather than silently dropping the excess, though no account this build was tested against is anywhere near that scale.
Every tick is a fresh snapshot, not a cursor
Unlike the audit-log push, which cursors forward by sequence number so nothing is missed, the metrics push carries no cursor at all. Every tick reads the current state and sends a fresh snapshot; a tick that fails, or a collector that is briefly unreachable, is simply a gap in your own time series, never a backlog to catch up on and never a redelivery concern. Treat a missing data point the way you would treat a missed scrape: as a gap, not as lost history, because the engine never tries to backfill one.
The 15-minute cadence can trip a default no-data monitor
The push rides the engine’s own reconciliation cron, which ticks every fifteen minutes, so a fresh data point lands no more often than that. Plenty of monitoring vendors default a “no data” or “missing metric” monitor to a much shorter window, commonly five to ten minutes, tuned for exporters that push far more often than this one does. Left at that default, the monitor can fire on every cycle, not because anything is actually unhealthy, but because it checked for freshness on a cadence tighter than the push’s own. Widen the no-data window to comfortably clear fifteen minutes, twenty to thirty gives headroom for a delayed tick, or use the pull-based /metrics scrape instead, where your own scrape interval controls the cadence end to end and this mismatch cannot arise.
Which vendors’ OTLP intake actually accepts this
This is the one place this page has to be more careful than the plan behind it assumed. The engine’s OTLP push is a hand-rolled OTLP/HTTP JSON body sent over a plain fetch() call, deliberately without a protobuf encoder: there is no protobuf runtime in a Cloudflare Worker here, and building one was out of scope. The OTLP/HTTP specification allows a server to accept either a binary protobuf body or a JSON-encoded one, but whether a given vendor’s own intake actually implements both is a per-vendor fact, not something this product can configure around.
| Vendor | Does its OTLP intake accept the JSON body this engine sends? |
|---|---|
| Datadog | Yes. Datadog’s documentation states its OTLP metrics intake accepts both HTTP protobuf and HTTP JSON. |
| New Relic | Unconfirmed. This page found no statement in New Relic’s own current documentation confirming JSON alongside protobuf for its OTLP/HTTP metrics intake, so treat New Relic as untested for this push until you verify it against a live account. |
| Dynatrace | No. Dynatrace’s OTLP ingest documentation states plainly that JSON is not supported for its OTLP metrics API; only the binary protobuf encoding is accepted. |
| Elastic Observability | No, not currently. Elastic’s APM Server accepts OTLP/HTTP only as binary protobuf today; JSON-encoded protobuf support is an open feature request against the project, not a shipped capability. |
| Splunk Observability Cloud | No. Its documented OTLP metrics endpoint accepts protobuf payloads only. |
Confirm this against your vendor's current documentation
Vendor intake behaviour changes over time and this table reflects each vendor’s own documentation as read while writing this page. Where a vendor is marked “No” above, this engine’s push cannot reach its direct OTLP intake as it stands, and where New Relic is marked “Unconfirmed”, this page simply could not find a primary-documentation answer either way, so do not rely on this push reaching it without testing it yourself first. For any of those four, point that vendor at the Prometheus /metrics endpoint instead, which every one of them ingests through a Prometheus-compatible agent or scrape config regardless of this JSON-versus-protobuf question, or interpose an OpenTelemetry Collector configured to receive OTLP/HTTP JSON and export OTLP/HTTP protobuf, which bridges the gap without any change to the engine.
Egress security
The outbound call inherits every guard the alert webhook and the SIEM push already carry: the endpoint must be https, a private, loopback, link-local or cloud-metadata address is refused by default at both configuration time and send time, a redirect is never followed, the request carries a timeout, and the response body is never read beyond its status. The auth header value is sealed at rest under its own domain-separated key, distinct from every other secret class this product seals, so it can never be resolved through another secret’s wrapping. The full screening model is described in securing notification webhooks; this destination is held to the same standard.
Where this fits
For the pull alternative this push exists alongside, read the Prometheus /metrics endpoint. For the audit-log push this feature’s egress hygiene and dual-control tier mirror, read forwarding the audit log to your SIEM (push). For the two-audience framing behind why this exists at all, read the monitoring overview. For the incident channels that turn a backup-health signal into an actual page, read incident channels.
Last updated .