Cloudflare Prometheus Exporter
Export Cloudflare metrics to Prometheus. Built on Cloudflare Workers with Durable Objects for stateful metric accumulation.
58 Prometheus metrics - requests, bandwidth, threats, workers, load balancers, SSL certs, and more
Cloudflare Workers - serverless edge deployment
Durable Objects - stateful counter accumulation for proper Prometheus semantics
Background refresh - alarms fetch data every 60s; scrapes return cached data instantly
Rate limiting - 40 req/10s with exponential backoff
Multi-account - automatically discovers and exports all accessible accounts/zones
Runtime config API - change settings without redeployment via REST endpoints
Configurable - zone filtering, metric denylist, label exclusion, custom metrics path, and more
Click the deploy button above. Configure CLOUDFLARE_API_TOKEN as a secret after deployment.
git clone https://github.com/cloudflare/cloudflare-prometheus-exporter.git
cd cloudflare-prometheus-exporter
bun install
wrangler secret put CLOUDFLARE_API_TOKEN
bun run deploy
Configuration is resolved in order: KV overrides β env vars β defaults . Use the Runtime Config API for dynamic changes without redeployment.
Set in wrangler.jsonc or via wrangler secret put:
Variable
Default
Description
CLOUDFLARE_API_TOKEN
-
Cloudflare API token (secret)
QUERY_LIMIT
10000
Max results per GraphQL query
SCRAPE_DELAY_SECONDS
300
Delay before fetching metrics (data propagation)
TIME_WINDOW_SECONDS
60
Query time window
METRIC_REFRESH_INTERVAL_SECONDS
60
Background refresh interval
LOG_LEVEL
info
Log level (debug/info/warn/error)
LOG_FORMAT
json
Log format (pretty/json)
ACCOUNT_LIST_CACHE_TTL_SECONDS
600
Account list cache TTL
ZONE_LIST_CACHE_TTL_SECONDS
1800
Zone list cache TTL
SSL_CERTS_CACHE_TTL_SECONDS
1800
SSL cert cache TTL
HEALTH_CHECK_CACHE_TTL_SECONDS
10
Health check cache TTL
EXCLUDE_HOST
false
Exclude host labels from metrics
CF_HTTP_STATUS_GROUP
false
Group HTTP status codes (2xx, 4xx, etc.)
DISABLE_UI
false
Disable landing page (returns 404)
DISABLE_CONFIG_API
false
Disable config API endpoints (returns 404)
METRICS_DENYLIST
-
Comma-separated list of metrics to exclude
CF_ACCOUNTS
-
Comma-separated account IDs to include (default: all)
CF_ZONES
-
Comma-separated zone IDs to include (default: all)
CF_FREE_TIER_ACCOUNTS
-
Comma-separated account IDs using free tier (skips paid-tier metrics)
METRICS_PATH
/metrics
Custom path for metrics endpoint
Quick setup : Create token with pre-filled permissions
Manual setup :
Permission
Access
Required
Zone > Analytics
Read
Yes
Account > Account Analytics
Read
Yes
Account > Workers Scripts
Read
Yes
Zone > SSL and Certificates
Read
Optional
Zone > Firewall Services
Read
Optional
Zone > Load Balancers
Read
Optional
Account > Logpush
Read
Optional
Account > Magic Transit
Read
Optional
Path
Method
Description
/
GET
Landing page (disable: DISABLE_UI)
/metrics
GET
Prometheus metrics
/health
GET
Health check ({"status":"healthy"})
/config
GET
Get all runtime config (disable: DISABLE_CONFIG_API)
/config
DELETE
Reset all config to env defaults (disable: DISABLE_CONFIG_API)
/config/:key
GET
Get single config value (disable: DISABLE_CONFIG_API)
/config/:key
PUT
Set config override (persisted in KV) (disable: DISABLE_CONFIG_API)
/config/:key
DELETE
Reset config key to env default (disable: DISABLE_CONFIG_API)
scrape_configs :
- job_name : ' cloudflare'
scrape_interval : 60s
scrape_timeout : 30s
static_configs :
- targets : ['your-worker.your-subdomain.workers.dev']
Override configuration at runtime without redeployment. Overrides persist in KV and take precedence over wrangler.jsonc env vars.
Key
Type
Description
queryLimit
number
Max results per GraphQL query
scrapeDelaySeconds
number
Delay before fetching metrics
timeWindowSeconds
number
Query time window
metricRefreshIntervalSeconds
number
Background refresh interval
accountListCacheTtlSeconds
number
Account list cache TTL
zoneListCacheTtlSeconds
number
Zone list cache TTL
sslCertsCacheTtlSeconds
number
SSL cert cache TTL
healthCheckCacheTtlSeconds
number
Health check cache TTL
logFormat
"json" | "pretty"
Log format
logLevel
"debug" | "info" | "warn" | "error"
Log level
cfAccounts
string | null
Comma-separated account IDs (null = all)
cfZones
string | null
Comma-separated zone IDs (null = all)
cfFreeTierAccounts
string
Comma-separated free tier account IDs
metricsDenylist
string
Comma-separated metrics to exclude
excludeHost
boolean
Exclude host labels
httpStatusGroup
boolean
Group HTTP status codes
# Get all config
curl https://your-worker.workers.dev/config
# Get single value
curl https://your-worker.workers.dev/config/logLevel
# Set override
curl -X PUT https://your-worker.workers.dev/config/logLevel \
-H " Content-Type: application/json" \
-d ' {"value": "debug"}'
# Filter to specific zones
curl -X PUT https://your-worker.workers.dev/config/cfZones \
-H " Content-Type: application/json" \
-d ' {"value": "zone-id-1,zone-id-2"}'
# Reset to env default
curl -X DELETE https://your-worker.workers.dev/config/logLevel
# Reset all overrides
curl -X DELETE https://your-worker.workers.dev/config
Metric
Type
Labels
cloudflare_zone_requests_total
counter
zone
cloudflare_zone_requests_cached
gauge
zone
cloudflare_zone_requests_ssl_encrypted
counter
zone
cloudflare_zone_requests_content_type
counter
zone, content_type
cloudflare_zone_requests_country
counter
zone, country, region
cloudflare_zone_requests_status
counter
zone, status
cloudflare_zone_requests_browser_map_page_views_count
counter
zone, family
cloudflare_zone_requests_ip_class
counter
zone, ip_class
cloudflare_zone_requests_ssl_protocol
counter
zone, ssl_protocol
cloudflare_zone_requests_http_version
counter
zone, http_version
cloudflare_zone_requests_origin_status_country_host
counter
zone, origin_status, country, host
cloudflare_zone_requests_status_country_host
counter
zone, edge_status, country, host
cloudflare_zone_request_method_count
counter
zone, method
Metric
Type
Labels
cloudflare_zone_bandwidth_total
counter
zone
cloudflare_zone_bandwidth_cached
counter
zone
cloudflare_zone_bandwidth_ssl_encrypted
counter
zone
cloudflare_zone_bandwidth_content_type
counter
zone, content_type
cloudflare_zone_bandwidth_country
counter
zone, country
Metric
Type
Labels
cloudflare_zone_threats_total
counter
zone
cloudflare_zone_threats_country
counter
zone, country
cloudflare_zone_threats_type
counter
zone, type
Metric
Type
Labels
cloudflare_zone_pageviews_total
counter
zone
cloudflare_zone_uniques_total
counter
zone
Metric
Type
Labels
cloudflare_zone_colocation_visits
counter
zone, colo, host
cloudflare_zone_colocation_edge_response_bytes
counter
zone, colo, host
cloudflare_zone_colocation_requests_total
counter
zone, colo, host
cloudflare_zone_colocation_visits_error
counter
zone, colo, host, status
cloudflare_zone_colocation_edge_response_bytes_error
counter
zone, colo, host, status
cloudflare_zone_colocation_requests_total_error
counter
zone, colo, host, status
Metric
Type
Labels
cloudflare_zone_firewall_events_count
counter
zone, action, source, rule, host, country
cloudflare_zone_firewall_bots_detected
counter
zone, bot_score, detection_ids
Metric
Type
Labels
cloudflare_zone_health_check_events_origin_count
counter
zone, health_status, origin_ip, region, fqdn, failure_reason
cloudflare_zone_health_check_events_avg
gauge
zone
cloudflare_zone_health_check_rtt_ms
gauge
zone, origin_ip, fqdn
cloudflare_zone_health_check_ttfb_ms
gauge
zone, origin_ip, fqdn
cloudflare_zone_health_check_tcp_conn_ms
gauge
zone, origin_ip, fqdn
cloudflare_zone_health_check_tls_handshake_ms
gauge
zone, origin_ip, fqdn
Metric
Type
Labels
cloudflare_worker_requests_count
counter
script_name
cloudflare_worker_errors_count
counter
script_name
cloudflare_worker_cpu_time
gauge
script_name, quantile
cloudflare_worker_duration
gauge
script_name, quantile
Metric
Type
Labels
cloudflare_zone_pool_health_status
gauge
zone, lb_name, pool_name
cloudflare_zone_pool_requests_total
counter
zone, lb_name, pool_name, origin_name
cloudflare_zone_lb_pool_rtt_ms
gauge
zone, lb_name, pool_name
cloudflare_zone_lb_steering_policy_info
gauge
zone, lb_name, policy
cloudflare_zone_lb_origins_selected_count
gauge
zone, lb_name, pool_name
cloudflare_zone_lb_origin_weight
gauge
zone, lb_name, pool_name, origin_name
Metric
Type
Labels
cloudflare_logpush_failed_jobs_account_count
counter
account, job_id, destination_type
cloudflare_logpush_failed_jobs_zone_count
counter
zone, job_id, destination_type
Metric
Type
Labels
cloudflare_zone_customer_error_4xx_rate
counter
zone, status, country, host
cloudflare_zone_customer_error_5xx_rate
counter
zone, status, country, host
cloudflare_zone_edge_error_rate
gauge
zone, status
cloudflare_zone_origin_error_rate
gauge
zone, status
cloudflare_zone_origin_response_duration_ms
gauge
zone, status, country, host
Metric
Type
Labels
cloudflare_zone_cache_hit_ratio
gauge
zone
cloudflare_zone_cache_miss_origin_duration_ms
gauge
zone, country, host
Metric
Type
Labels
cloudflare_zone_bot_request_by_country
counter
zone, country
Metric
Type
Labels
cloudflare_magic_transit_active_tunnels
gauge
account
cloudflare_magic_transit_healthy_tunnels
gauge
account
cloudflare_magic_transit_tunnel_failures
gauge
account
cloudflare_magic_transit_edge_colo_count
gauge
account
Metric
Type
Labels
cloudflare_zone_certificate_validation_status
gauge
zone, type, issuer, status
Metric
Type
Labels
cloudflare_exporter_up
gauge
-
cloudflare_exporter_errors_total
counter
account_id, error_code
cloudflare_accounts_total
gauge
-
cloudflare_zones_total
gauge
-
cloudflare_zones_filtered
gauge
-
cloudflare_zones_processed
gauge
-
cloudflare_zones_skipped_free_tier
gauge
-
Free Tier Zone Limitations
Zones on Cloudflare's Free plan don't have access to the GraphQL Analytics API. The exporter automatically detects and skips free tier zones for metrics that require this API.
Free tier zones still export:
cloudflare_zone_certificate_validation_status (SSL certificates)
cloudflare_zone_lb_origin_weight (Load balancer weights, if configured)
Monitor skipped zones:
cloudflare_zones_skipped_free_tier
For mixed accounts (enterprise + free zones), only free zones are skippedβpaid zones continue to export all metrics.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WORKER ISOLATE β
β ββββββββββββββββββ β
β β Worker.fetch βββββ HTTP /metrics, /health, /config β
β β (HTTP handler) β β
β βββββββββ¬βββββββββ β
β β β
β β RPC (stub.export()) β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β CONFIG_KV: Runtime config overrides (merged with env defaults) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DURABLE OBJECT ISOLATES β
β β
β Each DO runs in its own V8 isolate with: β
β - Own CloudflareMetricsClient instance (per-isolate singleton) β
β - Own persistent storage β
β - Own alarm scheduler β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β MetricCoordinator (1 global instance) β β
β β ID: "metric-coordinator" β β
β β State: accounts[], lastAccountFetch β β
β β Cache TTL: 600s (account list) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β RPC β
β ββββββββββββββΌβββββββββββββ β
β βΌ βΌ βΌ β
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ β
β β AccountMetric β β AccountMetric β β AccountMetric β β
β β Coordinator β β Coordinator β β Coordinator β β
β β account:acct1 β β account:acct2 β β account:acct3 β β
β β Alarm: 60s β β Alarm: 60s β β Alarm: 60s β β
β β Zone TTL: 1800s β β Zone TTL: 1800s β β Zone TTL: 1800s β β
β βββββββββ¬ββββββββββ βββββββββ¬ββββββββββ βββββββββ¬ββββββββββ β
β β RPC β β β
β ββββββββ΄ββββββ ββββββββ΄ββββββ ββββββββ΄ββββββ β
β βΌ βΌ βΌ βΌ βΌ βΌ β
β βββββββ βββββββ βββββββ βββββββ βββββββ βββββββ β
β βExprtβ βExprtβ βExprtβ βExprtβ βExprtβ βExprtβ β
β β(13) β .. β(N) β β(13) β .. β(N) β β(13) β .. β(N) β β
β βacct β βzone β βacct β βzone β βacct β βzone β β
β βββββββ βββββββ βββββββ βββββββ βββββββ βββββββ β
β β
β MetricExporter DOs (per account): β
β - Account-scoped (13): worker-totals, logpush-account, magic-transit, β
β http-metrics, adaptive-metrics, edge-country-metrics, colo-metrics, β
β colo-error-metrics, request-method-metrics, health-check-metrics, β
β load-balancer-metrics, logpush-zone, origin-status-metrics β
β - Zone-scoped (N per account, 1 per zone): ssl-certificates β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β CloudflareMetricsClient (per-isolate) β β
β β - urql Client (GraphQL) β β
β β - Cloudflare SDK (REST) β β
β β - DataLoader: firewallRulesLoader (batches Promise.all calls) β β
β β - Global Rate limiter: 40 req/10s with exponential backoff β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Request Path: Prometheus Scrape (GET /metrics)
ββββββββββββ GET /metrics ββββββββββ
βPrometheusββββββββββββββββββΆβ Worker β
β Server β β .fetch β
ββββββββββββ βββββ¬βββββ
β
ββββββββββββββββββββββββ΄βββββββββββββββββββββββ
β MetricCoordinator β
β β
β 1. Check account cache (TTL: 600s) β
β 2. If stale β getAccounts() β
β 3. Fan out to AccountMetricCoordinators β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββΌβββββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
ββββββββββββββββββ ββββββββββββββββββ ββββββββββββββββββ
β AccountMetric β β AccountMetric β β AccountMetric β
β Coordinator β β Coordinator β β Coordinator β
β (Account A) β β (Account B) β β (Account C) β
β β β β β β
β 1. Check if β β β β β
β refresh() β β (parallel) β β (parallel) β
β needed β β β β β
β 2. Fan out to β β β β β
β exporters β β β β β
βββββββββ¬βββββββββ βββββββββ¬βββββββββ βββββββββ¬βββββββββ
β β β
βββββββ΄ββββββ βββββββ΄ββββββ βββββββ΄ββββββ
βΌ βΌ βΌ βΌ βΌ βΌ
βββββββ βββββββ βββββββ βββββββ βββββββ βββββββ
βExprtβ...βExprtβ βExprtβ...βExprtβ βExprtβ...βExprtβ
β13+N β β β β13+N β β β β13+N β β β
β β β β β β β β β β β β
β ret β β ret β β ret β β ret β β ret β β ret β
βcacheβ βcacheβ βcacheβ βcacheβ βcacheβ βcacheβ
ββββ¬βββ ββββ¬βββ ββββ¬βββ ββββ¬βββ ββββ¬βββ ββββ¬βββ
β β β β β β
ββββββ¬βββββ ββββββ¬βββββ ββββββ¬βββββ
β β β
ββββββββββββββββββββββΌβββββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β FAN-IN: Merge β
β all metrics + β
β serialize to β
β Prometheus fmt β
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββ
β HTTP Response β
β text/plain β
βββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β NOTE: Request path is FAST - just reads cached metrics β
β No network calls to Cloudflare API during scrape β
β (unless account list cache is stale) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Background Refresh Path: Alarm-Driven Metric Fetching
ββββββββββββββββββββββββββββββββββββββββββββββββ
β ALARM TRIGGERS β
β AccountMetricCoordinator: every 60s β
β MetricExporter: every 60s + 1-5s fixed jitterβ
ββββββββββββββββββββββββββββββββββββββββββββββββ
AccountMetricCoordinator.alarm()
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AccountMetricCoordinator.refresh() β
β β
β 1. Check zone cache (TTL: 1800s / 30 min) β
β β
β 2. If stale: β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β REST: getZones(accountId) β β
β β βββΊ DataLoader batches if multiple calls same tick β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β REST: getFirewallRules(zoneId) Γ N zones (parallel) β β
β β βββΊ DataLoader batches parallel calls β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β 3. Push context to MetricExporter DOs: β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Account-scoped (13 exporters): β β
β β exporter.updateZoneContext(accountId, accountName, zones) β β
β β β β
β β Zone-scoped (N exporters, 1 per zone): β β
β β exporter.initializeZone(zone, accountId, accountName) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β 4. Schedule next alarm (60s) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
MetricExporter.alarm()
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MetricExporter.refresh() for account-scoped queries β
β β
β Query Types (13 total): β
β βββ ACCOUNT-LEVEL (single account per query, 3): β
β β βββ worker-totals β
β β βββ logpush-account β
β β βββ magic-transit β
β β β
β βββ ZONE-LEVEL (all zones batched in one query, 10): β
β βββ http-metrics β
β βββ adaptive-metrics β
β βββ edge-country-metrics β
β βββ colo-metrics β
β βββ colo-error-metrics β
β βββ request-method-metrics β
β βββ health-check-metrics β
β βββ load-balancer-metrics β
β βββ logpush-zone β
β βββ origin-status-metrics β
β β
β After fetch: Process counters β Cache metrics β Schedule next alarm β
β Jitter: 1-5s fixed (tighter clustering for time range alignment) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
bun install # Install dependencies
bun run dev # Run locally (port 8787)
bun run check # Lint + format check
bun run deploy # Deploy to Cloudflare
MIT