Hetzner Cloud metrics API: what it gives you and what it does not

The Hetzner Cloud metrics API gives CPU, disk and network per server and four load balancer metrics, 30 days back. No RAM, latency or per-target requests.

Author
Published
Last updated
Tags
explainer, hetzner, metrics, rate-limit

The Hetzner Cloud metrics API gives you CPU, disk and network for each server, and open connections, connections per second, requests per second and bandwidth for each load balancer. Hetzner keeps 30 days of both. You choose the step between samples, and Hetzner widens it so that a request returns at most 500 samples; every metrics request counts against the project’s API budget, 3,600 requests an hour by default. The API does not give you memory, disk space, queue depth, requests per target, latency or errors, and it never pushes anything: you poll.

Facts are from Hetzner’s API reference, changelog and documentation as read on 13 October 2026, from answers Hetzner support gave us in September 2026, and from our own tests, each marked where it appears.

What does the Hetzner Cloud API measure for a server?

GET /servers/{id}/metrics takes a type of cpu, disk or network, several in one call, and a start and end time. It returns these series:

Type Series Unit
cpu cpu percent
disk disk.0.iops.read, disk.0.iops.write operations/s
disk disk.0.bandwidth.read, disk.0.bandwidth.write bytes/s
network network.0.pps.in, network.0.pps.out packets/s
network network.0.bandwidth.in, network.0.bandwidth.out bytes/s

Every series comes back under metrics.time_series.<name>.values as [timestamp, "value"] pairs: the timestamp is Unix seconds, a number that can have a fraction, and the value is a string you convert to a number. start and end are RFC 3339 times, such as 2026-10-13T09:00:00Z. Two of the series are not what they look like.

CPU is counted per vCPU. The cpu series is not a 0 to 100 figure for the whole server: 100 is one vCPU’s worth of CPU time, one vCPU fully used or two at half, so a 4-vCPU server at full load reads 400. Divide by the server type’s vCPU count, server_type.cores in GET /servers/{id}, before you compare it with a threshold. Hetzner’s API reference has said so since early October 2026. We had measured it on 22 September 2026: with both vCPUs of a CX23 at full load for five minutes, the series averaged 199.9 and single samples reached 201.1, so expect readings a little above 100 per vCPU. What a raw reading does to a threshold is in what we measured on Hetzner.

Network is the public interface only. All four network series describe the public network interface. A load balancer reaches its targets over their public IPs unless a target is set to use its private IP (use_private_ip). With private IPs, which we recommend, the traffic the load balancer sends your servers does not appear in these series.

What does the Hetzner Cloud API measure for a load balancer?

GET /load_balancers/{id}/metrics takes four types, open_connections, connections_per_second, requests_per_second and bandwidth, all in one call if you like, and returns five series, because bandwidth comes as bandwidth.in and bandwidth.out.

Load balancer metrics cover the whole load balancer. No parameter or series refers to a target, so the API cannot tell you how many requests one server received. Per target, the API reports only health, and not from the metrics endpoint: GET /load_balancers/{id} lists each target’s status per service, healthy, unhealthy or unknown, and since 17 August 2026 the reason an unhealthy one failed and, for a wrong status code, the code it returned. Reading it is one more request. Hetzner’s load balancers also keep no log of individual requests; Hetzner’s advice is to log on the servers.

How long does Hetzner keep metrics, and at what resolution?

Hetzner keeps 30 days of metrics for servers and load balancers. You set the resolution with step, in seconds, and the answer tells you which step it used. Without it, Hetzner picks the step so that the window comes back in about 200 samples. With it, an answer still holds at most 500 samples, and Hetzner widens the step to fit. The reference does not say whether the cap counts each series or the whole answer, so when you ask for several types at once, check the step the answer reports. No minimum step is documented. In our test on 22 September 2026, with no step given, the API chose 3 seconds for a 10-minute window and 61 seconds for a 205-minute one.

Two consequences follow:

  • Thirty days at one-minute resolution take 87 requests for each server or load balancer you read. That is 43,200 minutes at 500 samples a request. When we read 30 days of one server’s CPU and one load balancer in September 2026, it took 174 requests.
  • The hcloud metrics commands cannot set a step. Up to hcloud 1.70.1, the current release in October 2026, hcloud server metrics and hcloud load-balancer metrics are marked alpha and take only --type, --start and --end, so a script built on them gets the step the API chooses: about 200 samples for the window, which for 30 days is one sample every 3.6 hours. To set a step, call the endpoint with hcloud api and -v step=60, or with any HTTP client.

Hetzner documents neither how fresh the newest sample is nor how a gap appears in an answer. In our test on 22 September 2026, one run on one 2-vCPU server, CPU only, read through hcloud at the 3-second step the API chose for a 10-minute window, the first sample at a new load level carried a timestamp 3 to 8 seconds after each of five load changes, and a read every 30 seconds first showed it 11 to 28 seconds after. In every read, the newest sample carried the end time of the window we asked for, so that timestamp alone does not tell you how old the data behind it is. We have not measured this at a 60-second step.

On 26 September 2026 we also saw that Hetzner dates a window’s points from the window’s start. Two of our polls, at 19:36:01 and 19:38:02, got the same minute back under two timestamps, 19:36:01 and 19:36:02, and our store kept both. Ask for a 60-second step, and start and end every window on a whole minute.

What does the Hetzner Cloud API not measure?

The API’s two metrics endpoints cover none of these; the server and load balancer objects add only the billing period’s traffic totals and, for a load balancer, each target’s health:

  • Memory. Hetzner’s documentation explains that its graphs are read from the host, and that RAM would need software inside your server, which Hetzner does not install.
  • Disk space. The disk series are operations and bytes per second, not how full the disk is.
  • Private network traffic, as above.
  • Queue depth, processes or anything from your application.
  • Requests per target, latency and errors. The load balancer reports totals and target health, nothing per request.
  • Alerts. Hetzner documents no alert on CPU, disk or load balancer metrics and no webhook. Its only notices are a notification to the project owner at 75% and 100% of included traffic, and an email when a cost alert you set is exceeded. Metrics are only ever polled.

Memory, disk space and anything from your application have to come from software on your own servers, such as an exporter on each one, and an alert from monitoring you run. Hetzner offers a Prometheus and Grafana app image: a new server with both pre-installed, activated when you first log in. Its documentation describes nothing that collects from your other servers.

How many metrics calls does the Hetzner API rate limit allow?

The Hetzner Cloud API allows 3,600 requests an hour per project by default, and metrics reads count against it like any other read. The budget refills by one request a second, bursts are allowed (Hetzner does not say how large), and a call over the limit fails with 429 and the error code rate_limit_exceeded. Answers to authenticated calls carry RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset; the last is the Unix time at which the whole budget is back, not the time of the next free request.

Hetzner support told us in September 2026 that the limit is per project, not per token, so a second token adds nothing, and that support can raise it for an account after a check. The same answer said that requests to action endpoints, such as waiting on an action or adding a load balancer target, run on a separate pool of 7,200 an hour; metrics reads and creating and deleting servers share the 3,600.

At one call a minute, each server or load balancer you poll costs 60 requests an hour, so 60 of them use the whole default budget. One server and one load balancer cost 120 an hour, about 3% of it. Three servers and one load balancer cost 240, about 7%. Twenty-five servers and one load balancer cost 1,560, 43%. Fifty servers alone cost 3,000, 83%, which leaves 600 an hour for creating and deleting servers and for every other tool on the project. Three habits keep a poller inside the budget:

  1. Ask for every type in one call. cpu,disk,network for a server costs the same request as cpu alone.
  2. Read servers less often as the fleet grows, but not more coarsely. Ask for the minutes since the last read with step=60: a read every five minutes then returns five one-minute samples, so you lose freshness, not resolution. Keep the load balancer, one call for all of its traffic, every minute.
  3. Keep a reserve. Watch RateLimit-Remaining and stop polling before it runs out, so the calls that change servers still find budget. Other tools on the project spend from the same budget, so a reserve lowers the risk of a 429 but cannot remove it.

Why should a missing Hetzner metric never count as zero?

Because a missing sample says something about the read, not about your load. A read can fail with 429 when the budget is spent, with 500, 502, 503 or 504 when Hetzner’s API cannot answer, or with 404 when the server is no longer in the project, and Hetzner documents nothing about how current or complete a series is. Read as zero, a missing sample looks like an idle server, and a loop that removes idle servers removes one whatever the real load, even at a peak.

The rule that follows is simple. Decide on a window of recent samples, allow at most one missing sample in it, nine of the ten minutes of a ten-minute window for example, and never fill a missing sample with zero or with the previous value. Never remove a server while any metric a scale-in rule needs is missing. And when a 429 arrives, stop polling until RateLimit-Remaining is back above your reserve, which at the default rate grows by 60 a minute, instead of retrying at once.

When are Hetzner’s metrics not enough to autoscale on?

The Hetzner Cloud metrics API is enough for one stateless web service behind a Hetzner load balancer, whose load shows up in its servers’ CPU and in the load balancer’s requests per second. It is not enough, and we would not autoscale on it alone, for:

  • Memory-bound applications, because there is no memory metric.
  • Queue workers, whose load is the queue, not their CPU.
  • Latency targets, because the API has no latency.
  • I/O-bound applications, where CPU stays low while the disk or the database is the limit. The API counts disk operations and bytes per second but reports no disk utilisation or wait time, and nothing from the database. The calculator warns about this too: for such an application its estimate is optimistic.

For those, the signal has to come from elsewhere: an exporter or an agent on the servers for memory, I/O and latency, and the queue itself for its depth. When the database is the limit, more servers do not help at all.

Where Hetscale fits

Hetscale works inside these limits. It reads each server’s CPU, divided by its vCPU count, and the load balancer’s requests and open connections. It reads the load balancer every minute, and each server’s CPU every minute while the node groups of your Hetzner project hold up to 25 servers, every 2 minutes up to 50 and every 5 minutes above that, always asking for one-minute samples. It stops reading before the project’s budget runs out, so the calls that create and delete servers keep a reserve. A rate-limited answer pauses decisions and is never read as a missing server, and missing data never removes one (what happens when metrics are missing). In our own test on 6 October 2026, with its metric reads switched off, an idle node group removed no server, and removed one only once nine of the ten minutes of its window had been read again. If you already run two or more servers from one image behind a Hetzner load balancer, the onboarding case for that setup starts with a report from their last 30 days of metrics.

Frequently asked questions

Does the Hetzner Cloud API report RAM usage? No. Server metrics are CPU, disk and network only. Memory needs software on the server, such as a Prometheus exporter.

How long does Hetzner keep server metrics? Thirty days, for servers and load balancers alike. Anything older has to be stored by you.

What is the Hetzner Cloud API rate limit? 3,600 requests an hour per project by default, refilled by one a second and shared by every tool that uses the project. Over the limit, calls fail with 429.

Why does my Hetzner CPU metric go above 100%? Because it is counted per vCPU: 100 is one vCPU’s worth of CPU time. Divide by the number of vCPUs of the server type.

Can I get alerts from Hetzner Cloud metrics? Not on CPU, disk or load balancer metrics. Hetzner only notifies you at 75% and 100% of included traffic, and emails you when a cost alert you set is exceeded. Poll the API, or run your own monitoring.

See what Hetscale would have done with your real data — connect read-only, get your report in minutes.

Connect read-only