ChirpStack to Grafana: Visualize LoRaWAN Data

Connect ChirpStack to Grafana via InfluxDB or TimescaleDB: the built-in InfluxDB integration, an MQTT to Telegraf path and a working datasource query.

LoRaWAN
Architecture

The data flow

Grafana does not speak LoRaWAN. It reads from a time-series datasource, so the real job is getting ChirpStack uplinks into InfluxDB or TimescaleDB first. This guide shows the built-in InfluxDB integration, an MQTT to Telegraf alternative and a working Grafana query.

Sensor / controller

Measures or controls in the field and sends LoRaWAN uplinks.

LoRaWAN gateway

Receives the radio packets and forwards them to the server.

ChirpStack

Network server: manages sessions and decodes the payload.

ThingsBoard / Grafana

Dashboards, alarms, rules and reports.

Why Grafana needs a datasource

Grafana is a dashboard and alerting layer. It does not run a LoRaWAN network server and it does not receive uplinks. It queries a datasource on a schedule and draws the result. So the integration is really two hops: ChirpStack writes decoded uplinks into a time-series store, and Grafana reads from that store.

There are two common stores:

  • InfluxDB is the shortest path, because ChirpStack ships a built-in InfluxDB integration. No extra code.
  • PostgreSQL with TimescaleDB suits teams already on PostgreSQL who want SQL, joins and relational device metadata next to the measurements.

This guide focuses on the InfluxDB path and then shows the MQTT to Telegraf alternative.

Prerequisite: a working payload codec

The InfluxDB integration writes the fields it finds in the decoded object. If the device profile has no codec, ChirpStack still publishes metadata (RSSI, SNR, frame counter) but no measurements, and your panels stay empty. Confirm the codec first, see ChirpStack payload decoder. A decoded uplink looks like this:

{
  "deviceInfo": {
    "applicationName": "cold-chain",
    "deviceProfileName": "EM300-TH",
    "deviceName": "coldroom-01",
    "devEui": "24e124136b502217"
  },
  "object": { "battery": 100, "temperature": 17.3, "humidity": 57.5 },
  "rxInfo": [{ "gatewayId": "24e124fffef54092", "rssi": -51, "snr": 13.8 }]
}

Only the keys under object become InfluxDB fields.

Step 1: Enable the InfluxDB integration

In the ChirpStack application, open Integrations and add InfluxDB. ChirpStack supports both InfluxDB versions:

  • InfluxDB v2: API endpoint, organization, bucket and an API token.
  • InfluxDB v1: endpoint, database, username and password.

For a v2 setup the values look like this:

Version:          InfluxDB v2
API endpoint:     https://influx.example.eu/api/v2/write
Organization:     merkaio
Bucket:           chirpstack
Token:            <write-token-from-influxdb>

Once enabled, every decoded uplink is written automatically. ChirpStack stores the device fields as measurements and adds tags such as the DevEUI and application, so you can filter per device in Grafana later.

Step 2: Add InfluxDB as a Grafana datasource

In Grafana go to Connections, Data sources, Add data source, InfluxDB. For InfluxDB v2 set the query language to Flux and fill in the matching connection details:

Query language:   Flux
URL:              https://influx.example.eu
Organization:     merkaio
Default bucket:   chirpstack
Token:            <read-token-from-influxdb>

Click Save & test and confirm the connection succeeds before building panels.

Step 3: Build the dashboard

Create a panel and query the field you want. With Flux, filter by measurement and field and group by the device tag so each device gets its own series:

from(bucket: "chirpstack")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r._measurement == "device_frmpayload_data_temperature")
  |> filter(fn: (r) => r._field == "value")
  |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
  |> group(columns: ["dev_eui"])

The exact measurement name depends on the integration version and the decoded field name; use the Grafana query inspector or the InfluxDB UI to read the real names from your data. From here you add humidity, battery and RSSI panels the same way and wire Grafana alert rules on top.

Alternative: MQTT to Telegraf to InfluxDB

If you want one collection pipeline for many sources, custom tagging or buffering, decouple ingestion from ChirpStack with Telegraf. Telegraf subscribes to the ChirpStack MQTT event topic, parses the JSON and writes to InfluxDB. A minimal telegraf.conf:

[[inputs.mqtt_consumer]]
  servers = ["tcp://mqtt.example.eu:1883"]
  topics  = ["application/+/device/+/event/up"]
  data_format = "json_v2"

  [[inputs.mqtt_consumer.json_v2]]
    measurement_name = "chirpstack"
    [[inputs.mqtt_consumer.json_v2.tag]]
      path = "deviceInfo.devEui"
      rename = "dev_eui"
    [[inputs.mqtt_consumer.json_v2.object]]
      path = "object"
      type = "float"

[[outputs.influxdb_v2]]
  urls         = ["https://influx.example.eu"]
  token        = "$INFLUX_TOKEN"
  organization = "merkaio"
  bucket       = "chirpstack"

Watch the region prefix: the ChirpStack v4 default config prepends the region to the topic (for example eu868/application/...). If Telegraf subscribes to application/# and the prefix is set, nothing arrives. Either subscribe with the prefix or remove it in chirpstack.toml.

PostgreSQL/TimescaleDB instead of InfluxDB

ChirpStack has no built-in PostgreSQL integration for application data, so this path needs a small consumer: an MQTT subscriber (or Node-RED style flow) that inserts each uplink into a TimescaleDB hypertable. The payoff is plain SQL in Grafana and easy joins against relational device metadata. The trade-off is the extra ingestion component you have to write and run.

Pitfalls from the field

  • Empty panels: Almost always a missing payload codec. No decoded object means no InfluxDB fields.
  • Token scope: ChirpStack needs a write token, Grafana needs a read token. Reusing one broad token works but is poor hygiene.
  • Measurement names: They are generated from the field names and differ slightly between integration versions. Read the real names from your data instead of guessing.
  • Retention: Set an InfluxDB retention policy early. LoRaWAN fleets are small per message but relentless, and unbounded buckets grow quietly.

Host the whole stack

ChirpStack, the time-series store and Grafana are three moving parts, plus the codecs and dashboards that make them useful. We build, wire and operate the full stack on European infrastructure as part of Grafana managed hosting alongside ChirpStack hosting, so you get dashboards instead of a backlog.

Frequently asked questions

No. Grafana is a visualization layer and only reads from a datasource. You first write ChirpStack uplinks into a time-series store like InfluxDB or PostgreSQL with TimescaleDB, then point Grafana at that store.
InfluxDB is the fastest path because ChirpStack has a built-in InfluxDB integration. TimescaleDB suits teams who already run PostgreSQL and want SQL, joins and relational metadata alongside the time series.
Yes. The integration supports both InfluxDB v1 and v2. For v2 you supply the API endpoint, organization, bucket and a token; for v1 you supply the database, username and password.
The InfluxDB integration only writes fields from the decoded object. Without a working payload codec on the device profile there are no numeric fields to store, only metadata, so most panels stay empty.
When you want one collection pipeline for many sources, custom tagging or buffering. Telegraf subscribes to the ChirpStack MQTT topic, parses the JSON and writes to InfluxDB, which decouples ingestion from ChirpStack.
Yes. We run the full stack as managed hosting on European infrastructure, including the integration, the datasource and ready-made dashboards. You keep ownership of the data.

Let's discuss your infrastructure. Digital and on-site.

Whether it's IoT platform development, hardware selection, managed hosting for ChirpStack, ThingsBoard, Grafana or NetBird VPN, or migration from a self-hosted setup - we'll find the right solution for your use case. Book a free 30-minute consultation, no commitment required.

Timo Wevelsiep

Your contact

Timo Wevelsiep

Founder, merkaio

15 minutes, no commitment, directly with Timo.

By submitting, you agree to our Privacy Policy.

merkaio is an independent integrator and is not affiliated with Milesight.