Node-RED

Node-RED JSON Node: Parsing MQTT JSON Payloads

How to handle JSON from MQTT in Node-RED: when to rely on the mqtt in node's parsed output, when to use the JSON node, how to validate with JSON Schema and how to fix the parse errors everyone hits.

Node-RED JSON node converting an MQTT payload string into a JavaScript object in a flow
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

The Node-RED JSON node converts between JSON strings and JavaScript objects, and it is the piece that decides whether msg.payload.temp works or returns undefined. This guide shows you how JSON arrives over MQTT, when to let the mqtt in node parse it for you, when to use the JSON node instead, how to validate payloads with a schema and how to fix the common parse errors.

Why MQTT Payloads Need Parsing

MQTT itself does not know about JSON. A broker carries every payload as raw bytes, whether those bytes are a number, a CSV line, a Protobuf message or a JSON document. When a temperature sensor publishes {"temp": 22.4, "hum": 41}, the subscriber receives 26 bytes and has to decide what they mean.

Node-RED gives you two places to make that decision: the Output option on the mqtt in node and the separate JSON node. Both use the same parser underneath. The difference is where the conversion happens and how much control you keep. If you want a refresher on how brokers route those bytes, see what an MQTT broker does.

Option 1: Let the mqtt in Node Parse JSON

Open any mqtt in node and look at the Output dropdown. Current Node-RED versions offer:

Output setting What msg.payload becomes Good for
auto-detect (parsed JSON object, string or buffer) Object if valid JSON, otherwise string, or Buffer for binary Mixed or unknown topics
a parsed JSON object Always an object; invalid JSON raises an error Topics you control that always carry JSON
a UTF-8 string String Plain text, CSV, payloads you parse yourself
a Buffer Node.js Buffer Binary formats such as Protobuf
a Base64 encoded string Base64 text Passing binary through text-only systems

For topics where every publisher sends JSON, "a parsed JSON object" is the cleanest choice. You get an object directly and a visible error when a device misbehaves. Auto-detect is convenient when you subscribe with a wide wildcard and some topics carry plain values like ON or 21.5, but it means downstream nodes must cope with either type.

Auto-detect works by trying to parse the payload: if it is valid JSON you get an object, otherwise you get a string, or a Buffer when the bytes are not valid text. That is convenient but less strict than the parsed JSON option.

Option 2: Use the Node-RED JSON Node

The JSON node sits anywhere in a flow and converts the property you choose. Its Action setting has three modes:

  • Convert between JSON String and Object: a string becomes an object, an object becomes a string. This is the default and is handy in both directions.
  • Always convert to JavaScript Object: strings are parsed; objects pass through unchanged.
  • Always convert to JSON String: objects are serialised; strings pass through unchanged. Tick Format JSON string to pretty-print with indentation.

You can also change the Property from payload to something else, such as payload.data, when a JSON document is nested as a string inside another document. That pattern shows up with gateways that wrap device messages in an envelope.

Use the JSON node rather than the mqtt in setting when:

  1. You subscribe once with a wildcard but only some branches carry JSON. Route with a Node-RED switch node first, then parse only the JSON branch.
  2. You need schema validation (covered below).
  3. The JSON is nested inside another property.
  4. You receive JSON from somewhere other than MQTT, such as an HTTP request or a file.

Try It on the Public Broker

The public MQTT test broker at broker.connectmq.com is a quick way to try every setting without installing anything. Publish a valid and an invalid payload from a terminal, replacing b52e with your own random string:

mosquitto_pub -h broker.connectmq.com -p 1883 -i demo-json-b52e \
  -t "connectmq/demo/b52e/room1/env" -m '{"temp": 22.4, "hum": 41}'

mosquitto_pub -h broker.connectmq.com -p 1883 -i demo-json-b52e \
  -t "connectmq/demo/b52e/room1/env" -m '{temp: 22.4}'

Then import this flow. It subscribes as a UTF-8 string and parses with a JSON node, so you can see both the success path and the error path.

[
  {"id":"tab1","type":"tab","label":"JSON demo"},
  {"id":"brk","type":"mqtt-broker","name":"ConnectMQ public","broker":"broker.connectmq.com","port":"1883","clientid":"nr-json-b52e","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true},
  {"id":"in","type":"mqtt in","z":"tab1","name":"env","topic":"connectmq/demo/b52e/+/env","qos":"0","datatype":"utf8","broker":"brk","x":110,"y":100,"wires":[["json"]]},
  {"id":"json","type":"json","z":"tab1","name":"parse","property":"payload","action":"obj","pretty":false,"x":270,"y":100,"wires":[["ok"]]},
  {"id":"ok","type":"debug","z":"tab1","name":"parsed","active":true,"complete":"payload","x":430,"y":100,"wires":[]},
  {"id":"catch","type":"catch","z":"tab1","name":"","scope":["json"],"uncaught":false,"x":110,"y":180,"wires":[["bad"]]},
  {"id":"bad","type":"debug","z":"tab1","name":"parse errors","active":true,"complete":"true","x":290,"y":180,"wires":[]}
]

The first message shows up in the "parsed" debug output as an expandable object. The second one triggers the Catch node, and the full message, including msg.error.message, appears under "parse errors". In production, wire that catch output to a counter or an alert topic instead of a debug node, so you know when a device firmware update starts sending broken JSON.

Validate Payloads with JSON Schema

Valid JSON is not the same as correct JSON. A device might send "temp": "22.4" as a string, or drop a field after a firmware change. The JSON node can check payloads against a JSON Schema: set msg.schema to a schema object before the node, and invalid messages raise an error with the validation details in msg.schemaError.

Set the schema with a Change node or a small function:

msg.schema = {
    type: "object",
    required: ["temp", "hum"],
    properties: {
        temp: { type: "number", minimum: -40, maximum: 125 },
        hum:  { type: "number", minimum: 0, maximum: 100 }
    },
    additionalProperties: true
};
return msg;

Put this before the JSON node and keep the Catch node from the demo. Messages that fail validation go to the error path with a readable reason, which is far easier to debug than chasing NaN values through a dashboard. Note that the schema is checked on the object side, so it works both when parsing a string and when the payload is already an object.

Publishing JSON Back to MQTT

The mqtt out node serialises objects automatically: if msg.payload is an object, it is sent as a JSON string. You do not need a JSON node before publishing in most flows. Add one with Always convert to JSON String only when you need a specific property serialised or want formatted output for human readers.

One subtle point: if you publish a number like 21.5 directly, the node sends the text 21.5. Subscribers using auto-detect will see that as valid JSON and give you a number, while subscribers set to UTF-8 will see a string. Pick one convention per topic and document it.

Troubleshooting Node-RED JSON Errors

Symptom Likely cause Fix
Unexpected token o in JSON at position 1 Payload is already an object and is parsed again Remove the extra JSON node or set mqtt in output to string
msg.payload.temp is undefined Payload is still a string Set mqtt in to parsed JSON or add a JSON node
Unexpected token } in JSON Trailing comma or unquoted keys from device firmware Fix the publisher; JSON requires quoted keys and no trailing commas
Debug shows a Buffer Output set to Buffer, or binary payload with auto-detect Use UTF-8 string or parsed JSON output
Numbers arrive as strings Publisher quotes values Validate with a schema and fix firmware, or convert with a Change node
Strange characters at start UTF-8 byte order mark from some tools Strip with a function node or fix the publisher

Most of these come from parsing twice or not at all. Add a debug node set to "complete msg object" right after mqtt in; the sidebar shows whether payload is a string, object or Buffer.

Best Practices Checklist

  1. Choose one parsing point per flow, either the mqtt in node or a JSON node, never both.
  2. Use "a parsed JSON object" for topics you own, and auto-detect only for mixed wildcards.
  3. Validate critical payloads with a schema and route failures through a Catch node.
  4. Keep payloads small and flat where possible; nested envelopes complicate every consumer.
  5. Put device identity in the topic, not only in the payload. Our Node-RED function node guide shows how to split the topic into fields.
  6. Document each topic's payload format alongside your topic naming plan.

For a complete beginner walkthrough, the Node-RED MQTT tutorial covers broker configuration, dashboards and alerts in one flow. The official guide to working with messages on nodered.org explains message structure and the JSON node in more depth.

Move Your JSON Flows to ConnectMQ

The public broker is shared and readable by anyone, so real device data belongs on a private broker. ConnectMQ is a fully managed MQTT service with TLS on port 8883 and a portal topic explorer where you can inspect the exact JSON each device publishes before it reaches Node-RED. Sign up at app.connectmq.com for the free Serverless plan, no credit card needed, then paste the generated credentials into your broker node and enable TLS. The free plan supports messages up to 256 KB, which is plenty for typical JSON telemetry.

Frequently Asked Questions

Do I need a JSON node after the mqtt in node?

Not if the mqtt in node's output is set to "a parsed JSON object" or auto-detect and the payload is valid JSON. Adding a JSON node as well can cause double-parsing errors.

How do I convert an object to a JSON string in Node-RED?

Use the JSON node with the action "Always convert to JSON String", optionally with Format JSON string for readable output. The mqtt out node also serialises objects automatically.

Can the JSON node validate data types?

Yes. Set msg.schema to a JSON Schema before the node, and messages that do not match raise an error you can handle with a Catch node, with details in msg.schemaError.

Why does auto-detect sometimes give me a number instead of an object?

A payload like 42 or true is valid JSON, so auto-detect parses it into a number or boolean. If you always expect an object, check the type in a Switch node or use a schema.

Related articles

Node-RED OPC UA Client to MQTT with ISA-95 Topics

Use node-red-contrib-opcua to subscribe to OPC UA variables on a PLC or simulation server, map node IDs to ISA-95 style MQTT topics, and publish values with quality and timestamps.

9 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.