MQTT’s JSON payloads can be more than just simple key-value pairs; they’re a flexible, albeit sometimes chaotic, way to send structured data from devices.

Let’s watch a message flow. Imagine a temperature sensor publishing to the topic iot/device/sensor1/data.

{
  "timestamp": 1678886400,
  "temperature": 22.5,
  "unit": "celsius",
  "battery": {
    "level": 85,
    "charging": false
  },
  "status": "ok"
}

A subscriber, perhaps a data processing service, receives this. It needs to extract temperature and battery.level.

The core problem MQTT JSON payloads solve is sending complex, nested data from constrained IoT devices in a human-readable and widely supported format. Instead of custom binary protocols or repetitive flat structures, JSON offers a schema-less, self-describing way to represent hierarchical information.

Internally, the MQTT broker just sees bytes. It doesn’t understand JSON. It routes the byte stream based on the topic string. The intelligence for interpreting the payload lies entirely with the publishing and subscribing applications. This is why consistency in your JSON structure is paramount.

The timestamp is a Unix epoch time. temperature is the reading, and unit clarifies it. The battery object nests two related pieces of information: its current level and whether it’s charging. status is a simple health indicator.

When designing these payloads, think about what information is essential, what is contextual, and what might change. For instance, adding a device_id to the payload itself, even though it’s also in the topic, can be useful if messages are ever logged or processed out of their original context.

{
  "device_id": "sensor1",
  "timestamp": 1678886400,
  "temperature": 22.5,
  "unit": "celsius",
  "battery": {
    "level": 85,
    "charging": false
  },
  "status": "ok"
}

The "schema-less" nature is a double-edged sword. While it offers flexibility, it means you must define and enforce your own schema. A common pattern is to have a separate schema registry or simply document the expected structure. For a simple setup, a quick check on the subscriber side can validate the incoming JSON.

Consider a Python subscriber using the paho-mqtt library:

import paho.mqtt.client as mqtt
import json

def on_message(client, userdata, msg):
    try:
        payload_str = msg.payload.decode("utf-8")
        data = json.loads(payload_str)

        # Basic validation
        if "timestamp" in data and "temperature" in data and "battery" in data and isinstance(data["battery"], dict) and "level" in data["battery"]:
            timestamp = data["timestamp"]
            temperature = data["temperature"]
            battery_level = data["battery"]["level"]
            print(f"Received data from {msg.topic}: Temp={temperature}°C, Battery={battery_level}%")
        else:
            print(f"Received malformed message on {msg.topic}: {payload_str}")

    except json.JSONDecodeError:
        print(f"Failed to decode JSON on topic {msg.topic}: {msg.payload.decode('utf-8')}")
    except Exception as e:
        print(f"An error occurred: {e}")

client = mqtt.Client()
client.on_connect = lambda client, userdata, flags, rc: print(f"Connected with result code {rc}")
client.on_message = on_message

client.connect("mqtt.eclipseprojects.io", 1883, 60)
client.subscribe("iot/device/sensor1/data")
client.loop_forever()

This code snippet demonstrates decoding the JSON, accessing nested fields like data["battery"]["level"], and performing a rudimentary check for expected keys. The json.loads() function is your primary tool for parsing.

A surprising aspect of JSON payloads in IoT is how often they are not validated by the broker, leaving the responsibility entirely to the endpoints. This means a single malformed message can break downstream processing if not handled robustly. Furthermore, using JSON adds overhead compared to more compact binary formats like Protocol Buffers or MessagePack, which can be a significant consideration for devices with very limited bandwidth or processing power.

The next logical step after structuring and parsing is to consider how to manage evolving schemas without breaking existing subscribers, a challenge often addressed by versioning your JSON structures within the topic or the payload itself.

Want structured learning?

Take the full Mqtt course →