ScaledObject, so your workloads scale on the same signals you already monitor and alert on. There is no need to run a separate Prometheus or push metrics to another system.
The integration uses KEDA’s built-in prometheus scaler: Metoro serves a Prometheus-compatible query endpoint that evaluates MetoroQL, so you configure a standard trigger type your team may already know, your API key rides in a TriggerAuthentication.
The
prometheus trigger is a stopgap: we plan to contribute a native metoro scaler type to KEDA, and once it merges upstream and reaches the KEDA release you run, trigger configuration becomes a first-class type: metoro with its own parameters. The endpoint behind it stays the same, existing prometheus triggers keep working, and this page will document the migration when the time comes.Prerequisites
- KEDA installed in your cluster (KEDA deployment docs).
- A Metoro API key. We recommend a dedicated key per cluster, bound to a read-only telemetry role (created in step 1 below).
Setup
1. Create a read-only telemetry role, group, and API key
The scaler only ever evaluates queries, so the key it uses needs no resource permissions at all: a role with nothing but telemetry read access follows least privilege, and if the key ever leaks it cannot read dashboards or alerts, change settings, or touch anything else in Metoro. Permissions flow role → group → key, so you create all three:- Create the role. In Settings → Users & Groups → Roles, click Create Role (say,
keda-autoscaler):- Grant no resource permissions. Custom roles are deny-by-default, so leaving them empty means the key can do nothing except what you grant next.
- Under Telemetry Permissions, grant the signals your scaling queries use:
metricsfor metric queries, plustracesorlogsif you scale on trace- or log-derived signals. If you do not yet know what you will scale on, just select all the signal types; the role is still read-only, and you can narrow it later. - Optionally scope the grants with match rules (for example to one namespace or environment). The scaler evaluates queries under the key’s telemetry scope, so a scoped role means scaling queries can only see the telemetry you granted, and a query outside that scope simply evaluates against no data.
- Create a group bound to the role. API keys are assigned to groups, not roles directly. In the Groups tab, create a group (say,
keda-autoscalers) and bind it to thekeda-autoscalerrole only. - Create the API key. From the API keys page, create the key assigned to just that group.
2. Store your API key in a Secret
3. Create a TriggerAuthentication
KEDA reads the key from the Secret and sends it to Metoro as a bearer token on every request. The key never appears in your ScaledObject specs, and rotating it is just updating the Secret.4. Create a ScaledObject
threshold: "100" means “aim for one replica per 100 requests per minute”. Keep the query an aggregate total like this (a total count, total connections, queue depth): the HPA divides the value across replicas itself under its default metric type, so per-pod averages produce wrong scaling math.
minReplicaCount: 1 is deliberate, not a placeholder. KEDA’s default is 0, and a signal emitted by the workload itself (like this one: the traces come from the checkout service serving requests) cannot wake a workload from zero, because at zero replicas there is nothing left to emit it. Only set minReplicaCount: 0 with a demand signal measured upstream of the workload that keeps reporting explicit zeros while it is absent, such as queue depth in a broker.
The query is the same MetoroQL the Metoro UI generates, written verbatim, so the easiest way to build one is to chart the signal in the metric explorer, confirm it looks right, and copy the query. What you see on the chart is exactly what KEDA scales on.
Trigger metadata reference
The standardprometheus scaler fields:
The Metoro parameters inside
queryParameters:
Debugging with curl
The endpoint speaks the Prometheus instant-query shape, so you can see exactly what KEDA sees:kubectl describe scaledobject.
Failure semantics
- Missing data is an error, not zero. If the window contains no datapoints, the endpoint returns
404witherrorType: no_datapointsrather than reporting 0. Many metrics are emitted infrequently or in batches, so an empty window often just means the next datapoint has not arrived yet; treating that as a literal 0 would scale your workload to minimum between emissions. Erroring instead lets the HPA hold replicas until data appears. If your metric is emitted infrequently, sizewindowcomfortably larger than the emission interval so the window always contains datapoints. - Stale data is an error. Metoro serves the scaling signal from a cache refreshed on KEDA’s polling cadence. An interruption in refresh is invisible for a while (the cached value keeps serving, holding your scale steady); past roughly ten minutes of failed refreshes the signal returns
503witherrorType: stale_datainstead of serving fiction. - Errors hold your current replica count. Any non-2xx response is a scaler error to KEDA: the HPA cannot compute a desired replica count, so it keeps the workload at whatever size the last good signal produced. This is the default and usually what you want: capacity tracks the last real measurement through an outage.
fallbackreplaces holding with a pinned count; use it deliberately. KEDA’sfallbackengages afterfailureThresholdconsecutive scaler errors and converges the workload tofallback.replicas, in both directions: a workload that was at 20 replicas when the signal failed gets scaled down to a fallback of 6. Configure it only if you specifically want a fixed known-safe capacity during outages (for example, if an outage coinciding with being scaled low worries you more than tracking the last measurement), and size it as safe capacity, not as a minimum. It also only applies toAverageValuemetrics (the default).
On-premises
The scaler ships in the Metoro on-prem chart, disabled by default. Enable it in your values:serverAddress: http://scaler.<metoro-namespace>.svc:8080 (plain HTTP, no TLS parameters needed). An optional ingress (scaler.ingress values) exposes it to KEDA operators in other clusters.
