Prometheus exporter and OpenTelemetry collector for the Cisco Meraki Dashboard API. Scrapes
device, network and MT sensor metrics into a /metrics endpoint and pushes native OTLP metrics.
Warning
I no longer have access to a Meraki network with anything other than MT, MR & MS devices. Changes affecting other device types (MX, MG, MV) are best-effort and driven from publicly available API documentation and SDK references rather than tested against live hardware. If you are willing to work with myself to boost support for other device types or add coverage please reach out! See the Support Matrix for exactly what is collected per product line.
A Prometheus exporter for Cisco Meraki Dashboard API metrics with OpenTelemetry tracing support.
- Complete device coverage: Collects metrics from all Meraki device types (MS, MR, MV, MT, MX, MG)
- Organization-level metrics: API usage, licenses, device counts, network health alerts
- Device-specific metrics: Status, performance, sensor readings, port statistics
- Webhook receiver: Real-time event processing from Meraki Dashboard alerts
- Client tracking: Optional DNS-enhanced client identification and monitoring (disabled by default)
- Network filtering: Restrict scraping to specific networks by name glob, ID, or tag (inactive by default)
- Status dashboard: Built-in
/statushealth UI alongside/cardinalityUI and/api/metrics/cardinalityJSON API
- High-performance collection: Parallel organization processing with bounded concurrency
- Shared inventory caching: Reduces duplicate org/network/device lookups with tier-aware TTLs
- Automatic metric expiration: Prevents stale metrics for offline/removed devices
- Retry-aware API client: Exponential backoff on rate limits with per-endpoint latency metrics
- Prometheus metrics:
/metricsendpoint for scraping - Distributed tracing: Full request tracing with OpenTelemetry instrumentation
- Structured logging: logfmt output with trace correlation and contextual information
- Cardinality monitoring: Built-in tracking and warning metrics for metric growth
- Health monitoring:
/healthand/readyprobes plus a/statusHTML dashboard summarising collector success rates, failure streaks, and last success timestamps
- Docker support with health checks and multi-stage builds
- Adaptive, budget-aware collection scheduling (per-endpoint-group solved intervals, no fixed tiers)
- Environment-based configuration with validation
- Regional API endpoint support
-
Copy
.env.exampleto.envand add your Meraki API key:cp .env.example .env # Edit .env and set: MERAKI_EXPORTER_MERAKI__API_KEY=your_api_key_here -
Run with Docker Compose:
docker compose up -d
-
Access metrics at http://localhost:9099/metrics
If you need to build the Docker image from source:
# Build the image
docker build -t meraki-dashboard-exporter .
# Run the container
docker run -d \
-e MERAKI_EXPORTER_MERAKI__API_KEY=your_api_key_here \
-p 9099:9099 \
meraki-dashboard-exporterNote
A locally-built image reports its version as 0.0.0+dev (and commit unknown)
on /status, the web UI, and meraki_exporter_build_info. Real version/commit
values are baked in only by CI-published images (via the APP_VERSION /
GIT_COMMIT build-args); pass --build-arg APP_VERSION=<v> --build-arg GIT_COMMIT=<sha>
to docker build if you want them on a local build.
The bundled docker-compose.yml healthcheck polls /health, which includes a
dead-man switch: it returns 503 (marking the container unhealthy) if no
collector has completed a successful run within the staleness threshold, so a
wedged exporter is restarted rather than left serving stale metrics.
A Helm chart is published to the GHCR OCI registry alongside every release, from
charts/meraki-dashboard-exporter:
helm install meraki-dashboard-exporter \
oci://ghcr.io/rknightion/charts/meraki-dashboard-exporter \
--version <exporter-version> \
--set meraki.apiKey=your_api_key_hereReplace <exporter-version> with a released version
(chart versions track exporter releases, e.g. 0.31.0), or use an existingSecret instead of
meraki.apiKey for production. See
values.yaml for all configurable settings and
the chart's CLAUDE.md for implementation notes. An
edge chart tracking main is also published on every push, versioned 0.0.0-main.*.
The exporter provides OpenTelemetry tracing when enabled:
Tracing: Distributed tracing for all operations
- Every Meraki API call is traced with timing and metadata
- Automatic instrumentation of HTTP, threading, and logging
- Configurable sampling rates for production use
- Correlation with logs via trace IDs
Logs: Structured logging with trace correlation
- Automatic trace context injection (trace_id, span_id)
- All logs include trace context when within a span
- Structured log fields preserved for easy parsing
- Compatible with log aggregation systems
Benefits:
- Prometheus metrics with traces and logs for correlation
- Debug slow API calls and identify bottlenecks
- Track request flow across the entire system
- Compatible with Jaeger, Tempo, Datadog, New Relic, etc.
Set these environment variables:
# Enable OTEL tracing
export MERAKI_EXPORTER_OTEL__ENABLED=true
# Set the OTEL collector endpoint
export MERAKI_EXPORTER_OTEL__ENDPOINT=http://localhost:4317
# Optional: Add resource attributes
export MERAKI_EXPORTER_OTEL__RESOURCE_ATTRIBUTES='{"environment":"production","region":"us-east"}'
# Optional: Configure trace sampling rate (default: 0.1 = 10%)
export MERAKI_EXPORTER_OTEL__SAMPLING_RATE=0.1services:
meraki-exporter:
image: meraki-dashboard-exporter
environment:
- MERAKI_EXPORTER_MERAKI__API_KEY=${MERAKI_EXPORTER_MERAKI__API_KEY}
- MERAKI_EXPORTER_OTEL__ENABLED=true
- MERAKI_EXPORTER_OTEL__ENDPOINT=http://otel-collector:4317
ports:
- "9099:9099"
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
ports:
- "4317:4317" # OTLP gRPC receiverSee docs/observability/otel.md for detailed OpenTelemetry configuration and docs/observability/tracing.md for distributed tracing documentation.
The exporter can receive webhook events from Meraki Dashboard. Webhooks accelerate device-down
detection only: a device_down/gateway_down event fast-flips meraki_device_up=0 ahead of the
next poll. Device recovery/UP and every other metric remain polled at DeviceCollector's own
solved cadence (~300s by default) — there is no whole-device "back online" webhook event to drive
a fast recovery path. See docs/data-freshness.md for the full staleness
picture and recommended alert for: durations.
# Enable webhook receiver
export MERAKI_EXPORTER_WEBHOOKS__ENABLED=true
# Set shared secret for validation (recommended)
export MERAKI_EXPORTER_WEBHOOKS__SHARED_SECRET=your_secret_here
# Optional: Require secret validation (default: true)
export MERAKI_EXPORTER_WEBHOOKS__REQUIRE_SECRET=true
# Optional: Maximum payload size in bytes (default: 1MB)
export MERAKI_EXPORTER_WEBHOOKS__MAX_PAYLOAD_SIZE=1048576- Navigate to Network-wide > Configure > Alerts
- Add a webhook receiver pointing to:
http://your-exporter:9099/api/webhooks/meraki - Set the shared secret to match your configuration
- Select which alert types to send
meraki_webhook_events_received_total: Total webhook events received by org and alert typemeraki_webhook_events_processed_total: Successfully processed webhook eventsmeraki_webhook_events_failed_total: Failed webhook event processingmeraki_webhook_processing_duration_seconds: Time spent processing webhook eventsmeraki_webhook_validation_failures_total: Validation failures by error type
All configuration is done via environment variables. See .env.example for all available options.
MERAKI_EXPORTER_MERAKI__API_KEY: Your Meraki Dashboard API key
MERAKI_EXPORTER_MERAKI__ORG_ID: Specific org ID to monitor. If unset, startup auto-selects the only visible org, but fails fast when the API key can see multiple orgs; deploy one instance per org. See the sharding recipe.MERAKI_EXPORTER_LOGGING__LEVEL: Logging level (default: INFO)MERAKI_EXPORTER_MERAKI__API_BASE_URL: API base URL for regional endpoints (default: https://api.meraki.com/api/v1)MERAKI_EXPORTER_API__TIMEOUT: API request timeout in seconds (default: 30)MERAKI_EXPORTER_API__MAX_RETRIES: Maximum API request retries (default: 3)MERAKI_EXPORTER_API__CONCURRENCY_LIMIT: Max parallel collector/org work (default: 5)MERAKI_EXPORTER_API__BATCH_SIZE: Default batch size for API operations (default: 20)MERAKI_EXPORTER_API__VALIDATE_KWARGS: Enable Meraki SDK kwarg validation warnings (default: false; recommended for dev/CI)MERAKI_EXPORTER_COLLECTORS__COLLECTOR_TIMEOUT: Per-run collector timeout budget in seconds (default: 240)MERAKI_EXPORTER_CLIENTS__ENABLED: Enable client collector and DNS resolution (default: false)MERAKI_EXPORTER_WEBHOOKS__ENABLED: Enable Meraki webhook receiver (default: false)MERAKI_EXPORTER_SERVER__API_TOKEN: Bearer token that enables the two state-changing control POSTs (/api/collectors/trigger,/api/clients/clear-dns-cache). When unset (default), those POSTs fail closed with HTTP 401 and their UI controls are disabled. When configured, the controls are API-only and hidden from the browser. The sensitive GET UIs remain open by default; bind the exporter to a trusted network or disable them. See security.md.- Beta / early-access API: the exporter never calls Meraki's beta endpoints and has no opt-in flag (they are unversioned and would undermine the v1 stability promise). It instead surfaces the risk —
meraki_org_has_beta_api(1/0per org) plus a WARN log fire when an org is on the beta Dashboard spec, which can silently break assumed-stable collection. Alert onmeraki_org_has_beta_api == 1. See security.md.
There is no fixed FAST/MEDIUM/SLOW tier system. Every API fetch is grouped into an endpoint group with its own volatility floor, and an adaptive, budget-aware scheduler solves each group's actual polling interval from organization size and the configured API budget, automatically stretching lower-priority groups when demand would exceed it. See Scheduler Architecture for the full mechanism.
MERAKI_EXPORTER_SCHEDULER__MODE:adaptive(default) orfixed(floors/pins only, no stretching)MERAKI_EXPORTER_SCHEDULER__TARGET_UTILIZATION: Fraction of the effective budget the solver plans to (default: 0.7)MERAKI_EXPORTER_SCHEDULER__MAX_STRETCH_FACTOR: Per-group interval cap as a multiple of its floor (default: 4.0)MERAKI_EXPORTER_SCHEDULER__MAX_INTERVAL_SECONDS: Absolute per-group interval cap (default: 3600)MERAKI_EXPORTER_SCHEDULER__RESOLVE_INTERVAL_SECONDS: How often the solver recomputes from org shape (default: 900)MERAKI_EXPORTER_SCHEDULER__FAILURE_RETRY_SECONDS: Minimum spacing between retries of a failing group (default: 300)MERAKI_EXPORTER_SCHEDULER__GROUP_INTERVAL_OVERRIDES: Per-group interval pins as a JSON object, e.g.{"nh_connection_stats": 900}MERAKI_EXPORTER_COLLECTORS__MAX_CONCURRENT_COLLECTORS: Max collectors whose group-clocked loops may run concurrently (default: 5)
Restrict the exporter to a subset of networks. All fields are optional comma-separated lists; if every field is empty, every network in every configured organisation is scraped (the default).
# Include only networks whose name matches a glob (case-sensitive)
MERAKI_EXPORTER_NETWORK_FILTER__INCLUDE_NAMES=prod-*,staging-*
# Or by exact network ID
MERAKI_EXPORTER_NETWORK_FILTER__INCLUDE_IDS=L_123,L_456
# Or by network tag (any match wins)
MERAKI_EXPORTER_NETWORK_FILTER__INCLUDE_TAGS=production,critical
# Exclude rules (applied AFTER includes)
MERAKI_EXPORTER_NETWORK_FILTER__EXCLUDE_NAMES=*-test
MERAKI_EXPORTER_NETWORK_FILTER__EXCLUDE_IDS=L_999999
MERAKI_EXPORTER_NETWORK_FILTER__EXCLUDE_TAGS=labSemantics. If any INCLUDE_* field is set, a network must match at least one include rule (across name OR id OR tag) to be considered. Then any matching EXCLUDE_* rule drops it. Empty resolution at startup fails fast.
Devices in excluded networks are not scraped either. Organization-level metrics (license counts, API usage) are unaffected.
Observability. Live filter state is published as meraki_network_filter_match{org_id,network_id} (value 1 if included, 0 if excluded), meraki_network_filter_resolved{org_id}, and meraki_network_filter_total{org_id} so dashboards and alerts can verify filter scope.
For users in specific regions, use the appropriate API base URL:
- Global/Default:
https://api.meraki.com/api/v1 - Canada:
https://api.meraki.ca/api/v1 - China:
https://api.meraki.cn/api/v1 - India:
https://api.meraki.in/api/v1 - US Federal:
https://api.gov-meraki.com/api/v1
Example:
export MERAKI_EXPORTER_MERAKI__API_BASE_URL="https://api.meraki.ca/api/v1" # For Canada regionThe exporter exposes /metrics, health/readiness probes (/health, /ready), a
/status dashboard, the client and cardinality UIs, and a few control/webhook
POSTs. See the generated HTTP Endpoints reference
for the authoritative list (method, path, and which config flag gates each one),
kept in sync via uv run python scripts/generate_endpoints_docs.py.
- Organization & license metrics: API usage, device/network counts, licenses, configuration, and alerts
- Device metrics: Availability, status info, switch port health (including per-second error rates), AP performance, camera/sensor readings, and gateway connectivity
- Network health metrics: RF/channel utilization, connection stats, Bluetooth sightings, and data rates
- Client metrics (optional): Per-client status and usage when
MERAKI_EXPORTER_CLIENTS__ENABLED=true - Webhook metrics (optional): Event counts, validation failures, and processing duration for
POST /api/webhooks/meraki - Infrastructure metrics: Collector duration/error counts, parallel collection activity, API latency/counters, inventory cache hits/misses/size, and metric expiration tracking
- Cardinality monitoring:
/cardinalityHTML report and/api/metrics/cardinalityJSON API for top-k series growth
See the generated metrics reference for the authoritative metric list (kept in sync via uv run python scripts/generate_metrics_docs.py).
Metric-name, label, and unit compatibility is governed by the Metric Stability & Deprecation Policy, which defines the Stable vs Experimental tiers, the 1.0 promise, and the post-1.0 rename process.
- Bounded concurrency: ManagedTaskGroup keeps parallel collectors/orgs within
MERAKI_EXPORTER_API__CONCURRENCY_LIMIT;MERAKI_EXPORTER_COLLECTORS__MAX_CONCURRENT_COLLECTORSseparately bounds how many collectors' own loops run concurrently - Adaptive scheduling: each collector runs its own group-clocked loop; the scheduler solves per-endpoint-group intervals from data volatility floors (~60s/300s/900s+ typical) and the API budget, stretching lower-priority groups automatically under pressure — see docs/observability/scheduler.md
- Inventory-routed lookups: Collectors fetch network/device data through the shared
OrganizationInventorycache to suppress duplicate API calls - Batch controls: Tunable batch sizes and delays (
MERAKI_EXPORTER_API__*BATCH_SIZE,MERAKI_EXPORTER_API__BATCH_DELAY) - Adaptive smoothing: Per-collector batch smoothing spreads work across the interval, capped at 30% of
MERAKI_EXPORTER_COLLECTORS__COLLECTOR_TIMEOUTso a single collector cannot starve the run budget - Metric lifecycle: Automatic expiration cleans up stale series when devices disappear or go offline
uv run pytestuv run ruff check .
uv run mypy .MIT