Azure Service Bus Integration
Azure Service Bus Integration receives messages from a topic subscription in Azure Service Bus. An uplink data converter transforms each message into device or asset data, including telemetry and attributes. ThingsBoard can also publish downlink messages to a separate Service Bus topic.
Use Azure Service Bus Integration when:
- Your applications or IoT platforms already publish device data to a Service Bus topic.
- Several consumers must read the same data: each topic subscription receives its own copy of every message.
- Backend services must receive commands or data from ThingsBoard through a Service Bus topic.
Architecture
Section titled “Architecture”- Receive data. A producer sends a message to the uplink topic. The integration receives it from its subscription on that topic.
- Decode the payload. The uplink converter identifies the target device or asset from the payload and extracts attributes and telemetry.
- Process the message. ThingsBoard processes the converted data through the Rule Engine. If Allow create devices or assets is enabled, ThingsBoard can create an entity that does not exist yet.
- Send downlink data (optional). The Rule Engine passes a message to the integration. The downlink converter encodes it, and the integration publishes it to the downlink topic.
Prerequisites
Section titled “Prerequisites”- Access to ThingsBoard or ThingsBoard Cloud with integrations enabled for your tenant.
- Permission to create integrations and data converters, and to edit rule chains for downlink.
- An Azure account with an active subscription and permission to create a Service Bus namespace.
- Outbound TCP port
5671(AMQP) open from the ThingsBoard server to*.servicebus.windows.net.
Configure Azure Service Bus
Section titled “Configure Azure Service Bus”Create a namespace, the uplink and downlink topics with their subscriptions, and copy the connection string. For details, see Create Service Bus topics and subscriptions.
Create a Namespace
Section titled “Create a Namespace”- In the Azure portal, click + Create a resource, search for Service Bus, and click Create.
- On the Basics tab, select or create a Resource group, enter a globally unique Namespace name, and choose a Location.
- Set Pricing tier to Standard or Premium. The Basic tier does not support topics.
- Click Review + create, then Create.
- When the deployment finishes, click Go to resource.
Create Topics and Subscriptions
Section titled “Create Topics and Subscriptions”The integration reads from a topic subscription, not from a queue. Downlinks go to a second topic. A message sent to a topic without subscriptions is discarded, so the downlink topic also needs a subscription for its consumer.
- In the namespace, go to Entities ⇾ Topics and click + Topic.
- Enter the name
uplinktopicand click Create. - Open
uplinktopic, click + Subscription, enterS1, and click Create. ThingsBoard reads from this subscription. - Repeat steps 1–3 for the downlink: a topic
downlinktopicwith a subscriptionS2. Skip this if you do not need downlink.
Each subscription keeps its own copy of every topic message. Give ThingsBoard a subscription that no other application reads.
Copy the Connection String
Section titled “Copy the Connection String”- In the namespace, go to Settings ⇾ Shared access policies.
- Click + Add, enter a Policy name, for example
thingsboard, select Send and Listen, and click Create. Listen is needed for uplink, Send for downlink. - Open the policy and copy the Primary Connection String. It has the form
Endpoint=sb://<namespace>.servicebus.windows.net/;SharedAccessKeyName=thingsboard;SharedAccessKey=<key>.
For a quick test, the default RootManageSharedAccessKey policy also works, but it grants full control of the namespace.
You now have the values for the integration:
| Value | Example | Source |
|---|---|---|
| Connection string | Endpoint=sb://…;SharedAccessKeyName=thingsboard;SharedAccessKey=… |
Policy details page |
| Topic name | uplinktopic |
Uplink topic |
| Subscription name | S1 |
Subscription on the uplink topic |
| Downlink topic name | downlinktopic |
Downlink topic. Needed only for downlink. |
Set Up Azure Service Bus Integration
Section titled “Set Up Azure Service Bus Integration”Create the uplink converter, assign it to a new Azure Service Bus integration, and send a test message.
Create the Uplink Data Converter
Section titled “Create the Uplink Data Converter”The uplink converter receives each message body as a byte array, resolves the target device, and returns its telemetry and attributes. Azure Service Bus Integration uses the Generic converter: you write the decoder in TBEL or JavaScript. For converter types and the full decoder reference, see Uplink data converter.
This guide uses the sample payload that ThingsBoard provides for Azure Service Bus converters, with a recent timestamp:
{ "deviceId": "8F4A2C6D", "deviceType": "Packing machine", "temperature": 25.5, "pressure": 1013.25, "vibration": { "x": 0.02, "y": 0.03, "z": 0.015 }, "location": { "latitude": 37.7749, "longitude": -122.4194, "altitude": 10 }, "timestamp": "2026-10-14T10:30:00Z", "status": "ALARM", "alarms": [ { "type": "temperature", "severity": "high", "message": "Temperature exceeds threshold." }, { "type": "vibration", "severity": "critical", "message": "Excessive vibration detected." } ], "metadata": { "version": 1, "batteryLevel": 100, "batteryStatus": "Charging", "manufacturer": "Example corporation" }}-
Go to Integrations ⇾ Data converters and click + Add data converter ⇾ Create new converter.
-
Converter type — keep Uplink.
-
Integration type — select Azure Service Bus.
-
Name — enter a name, for example
Azure Service Bus Uplink Converter. -
Main decoding configuration — the editor opens with the default Azure Service Bus template. Replace it with the decoder below. The decoder maps measurements and state to telemetry and static device properties to attributes. It also reads
timestamp,location, andvibrationwhen the payload carries them. The editor opens in TBEL; use the TBEL / JS toggle to switch to JavaScript.var data = decodeToJson(payload);var deviceName = data.deviceId != null ? data.deviceId : "Device A";var deviceType = data.deviceType != null ? data.deviceType : "default";// ISO 8601 timestamp; fall back to server time.var ts = data.timestamp != null ? new Date(data.timestamp).getTime() : Date.now();// Static device properties become attributes.var attributes = {};if (data.location != null) {attributes.latitude = data.location.latitude;attributes.longitude = data.location.longitude;attributes.altitude = data.location.altitude;}if (data.metadata != null) {attributes.version = data.metadata.version;attributes.manufacturer = data.metadata.manufacturer;}// Measurements and state become telemetry.var telemetry = {temperature: data.temperature,pressure: data.pressure,status: data.status,receivedAlarms: data.alarms};if (data.vibration != null) {telemetry.vibrationX = data.vibration.x;telemetry.vibrationY = data.vibration.y;telemetry.vibrationZ = data.vibration.z;}if (data.metadata != null) {telemetry.batteryLevel = data.metadata.batteryLevel;telemetry.batteryStatus = data.metadata.batteryStatus;}return {deviceName: deviceName,deviceType: deviceType,attributes: attributes,telemetry: {ts: ts,values: telemetry}};var data = decodeToJson(payload);var deviceName = data.deviceId != null ? data.deviceId : "Device A";var deviceType = data.deviceType != null ? data.deviceType : "default";// ISO 8601 timestamp; fall back to server time.var ts = data.timestamp != null ? new Date(data.timestamp).getTime() : Date.now();// Static device properties become attributes.var attributes = {};if (data.location != null) {attributes.latitude = data.location.latitude;attributes.longitude = data.location.longitude;attributes.altitude = data.location.altitude;}if (data.metadata != null) {attributes.version = data.metadata.version;attributes.manufacturer = data.metadata.manufacturer;}// Measurements and state become telemetry.var telemetry = {temperature: data.temperature,pressure: data.pressure,status: data.status,receivedAlarms: data.alarms};if (data.vibration != null) {telemetry.vibrationX = data.vibration.x;telemetry.vibrationY = data.vibration.y;telemetry.vibrationZ = data.vibration.z;}if (data.metadata != null) {telemetry.batteryLevel = data.metadata.batteryLevel;telemetry.batteryStatus = data.metadata.batteryStatus;}var result = {deviceName: deviceName,deviceType: deviceType,attributes: attributes,telemetry: {ts: ts,values: telemetry}};// Convert the byte array to a string.function decodeToString(payload) {return String.fromCharCode.apply(String, payload);}// Convert the byte array to a JSON object.function decodeToJson(payload) {return JSON.parse(decodeToString(payload));}return result;To adapt:
- Device name in another field — replace
data.deviceId, for example withdata.serialNumber. - Device name in a message property — if the producer sets a custom property, for example
deviceId, read it withmetadata["sysProp:deviceId"]. - Optional fields — remove the
location,vibration,status, oralarmsmappings your devices never send. - Other telemetry — add keys to
telemetry, for examplehumidity: data.humidity. - Other device properties — add them to
attributes, for examplemodel: data.model. - Update-only keys — for Azure Service Bus, ThingsBoard pre-fills the Update only keys list in Advanced decoding parameters with
manufacturer,receivedAlarms,status,batteryLevel,batteryStatus, andversion. These keys are stored only when their value changes. Edit the list to match your keys.
- Device name in another field — replace
-
Click Test decoder function and check the result (see Test the Decoder).
-
Click Add.
Decoder Inputs
The decoder signature is function decoder(payload, metadata): object | object[].
| Variable | Type | Content |
|---|---|---|
payload |
byte array | The message body. |
metadata |
{[key: string]: string} |
Each custom (application) property of the message as sysProp:<name>. Also integrationName and the key–value pairs from the integration’s Metadata field. Broker properties such as MessageId or ContentType are not passed. |
Built-in helpers:
| Function | Result |
|---|---|
decodeToJson(payload) |
Parses the bytes as JSON and returns an object. |
decodeToString(payload) |
Converts the bytes to a UTF-8 string. |
toFlatMap(obj, excludeKeys, flatNested) |
TBEL only. Returns a flat key–value map of obj, skipping excludeKeys. With flatNested set to true, nested objects become dot-separated keys. |
For field renaming, nested values, and non-JSON payloads, see Common scripting patterns.
Test the Decoder
Click Test decoder function below the editor. Replace the content of Payload with the sample payload. Click Test. The Output panel shows:
{ "deviceName": "8F4A2C6D", "deviceType": "Packing machine", "attributes": { "latitude": 37.7749, "longitude": -122.4194, "altitude": 10, "version": 1, "manufacturer": "Example corporation" }, "telemetry": { "ts": 1791973800000, "values": { "temperature": 25.5, "pressure": 1013.25, "status": "ALARM", "receivedAlarms": [ { "type": "temperature", "severity": "high", "message": "Temperature exceeds threshold." }, { "type": "vibration", "severity": "critical", "message": "Excessive vibration detected." } ], "vibrationX": 0.02, "vibrationY": 0.03, "vibrationZ": 0.015, "batteryLevel": 100, "batteryStatus": "Charging" } }}ts is the payload’s timestamp, 2026-10-14T10:30:00Z, in milliseconds.
Check that deviceName is set and telemetry holds the expected keys. If the output is empty or shows an error, fix the decoder and test again.
Create the Integration
Section titled “Create the Integration”- Go to Integrations ⇾ Integrations and click + Add integration.
- Basic settings:
- Integration type — select Azure Service Bus.
- Name — keep the default or enter your own.
- Enable integration and Allow create devices or assets — keep both on, so the device is created on its first uplink.
- Click Next.
- Uplink data converter:
- Click Select existing and choose
Azure Service Bus Uplink Converter. - Alternatively, click Create new to write a decoder here.
- Click Next.
- Click Select existing and choose
- Downlink data converter:
- Click Skip. Add a downlink converter later if you need to publish to Service Bus.
- Connection:
- Connection string — paste the Primary Connection String.
- Topic name — enter
uplinktopic. - Subscription name — enter
S1. - See Connection Settings for details.
- Click Add.
Connection Settings
Section titled “Connection Settings”| Parameter | Description |
|---|---|
| Connection string | Namespace connection string of a policy with Listen permission. Required. |
| Topic name | Topic the integration receives from. Required. |
| Subscription name | Subscription on that topic. Required. |
| Execute remotely | Runs the integration as a separate process outside the ThingsBoard cluster, for example in a network with access to Azure. ThingsBoard generates an Integration key and Integration secret for it. See Remote Integration. |
Advanced settings
| Parameter | Description |
|---|---|
| Downlink connection string | Connection string of a policy with Send permission on the namespace of the downlink topic. It can be the same namespace and string as for uplink. Required when a downlink converter is assigned. |
| Downlink topic name | Topic the integration publishes downlinks to. Required when a downlink converter is assigned. |
| Description | Free-text description. |
| Metadata | Key–value pairs added to the metadata of every message from this integration. |
Check connection validates only the format of the connection string. It does not connect to the topic, so wrong names or keys show up as missing uplinks.
The integration removes each message from the subscription after processing it, including messages the converter fails to decode. Check Error events in the converter to catch them.
Test Uplink
Section titled “Test Uplink”Send a message to the uplink topic, then confirm that ThingsBoard decoded it and created the device.
Send a Test Uplink
Section titled “Send a Test Uplink”Send the sample payload without timestamp. The decoder then uses the current server time; with a fixed timestamp, the data would fall outside the recent time windows of your dashboards as time passes.
-
In the namespace, go to Entities ⇾ Topics and open
uplinktopic. -
Click Service Bus Explorer in the topic menu, then click Send messages.
-
Set Content Type to Application/Json.
-
Paste the payload into Message body:
{"deviceId": "8F4A2C6D","deviceType": "Packing machine","temperature": 25.5,"pressure": 1013.25,"vibration": {"x": 0.02,"y": 0.03,"z": 0.015},"location": {"latitude": 37.7749,"longitude": -122.4194,"altitude": 10},"status": "ALARM","alarms": [{"type": "temperature","severity": "high","message": "Temperature exceeds threshold."},{"type": "vibration","severity": "critical","message": "Excessive vibration detected."}],"metadata": {"version": 1,"batteryLevel": 100,"batteryStatus": "Charging","manufacturer": "Example corporation"}} -
Click Send.
Service Bus Explorer needs the Service Bus Data Owner or Service Bus Data Sender role on the namespace.
Verify the Result
Section titled “Verify the Result”- Integration events — go to Integrations ⇾ Integrations, open the integration, and click the Events tab. The uplink appears with status OK. Click
⋅⋅⋅in the Message column to see the message:systemProperties(the custom properties) andpayload. - Converter events — open
Azure Service Bus Uplink Converterin Integrations ⇾ Data converters and click the Events tab. In shows the received payload, Out shows the decoded result, and Metadata shows the integration name and anysysProp:values. - Device — go to Devices & assets ⇾ Devices. The integration has created 8F4A2C6D with the
Packing machineprofile. Open it and check the Latest telemetry tab fortemperature,pressure,status,receivedAlarms,vibrationX–vibrationZ,batteryLevel, andbatteryStatus, and the Attributes tab forlatitude,longitude,altitude,version, andmanufacturer.
Configure Downlink
Section titled “Configure Downlink”ThingsBoard publishes a downlink when the Rule Engine routes a message to the integration — for example, after a shared attribute update. The integration sends it to the Downlink topic name. Every subscription on that topic receives a copy, and your backend reads it from its subscription.
Each downlink message carries:
- Body — the encoder’s
data. - Content type — the encoder’s
contentType:JSON,TEXT, orBINARY. - To — the encoder’s
metadata.deviceId. Consumers can filter or route on it. - Custom properties — every key of the encoder’s
metadata.
The downlink converter turns a Rule Engine message into the published message. For the full encoder reference, see Downlink data converter.
Create and Assign the Downlink Converter
Section titled “Create and Assign the Downlink Converter”The encoder must set metadata.deviceId. Without it, the integration skips the message.
- Open the integration in Integrations ⇾ Integrations and click Toggle edit mode (pencil icon).
- In the Downlink data converter field, click Create new. The Downlink converter type and Azure Service Bus integration type are preselected.
- Enter a name, for example
Azure Service Bus Downlink Converter. - In Main encoding configuration, replace the default encoder with the one below.
- To record downlink events, click the debug icon next to the name, select All messages, and click Apply.
- Click Add.
- In Advanced settings, fill in:
- Downlink connection string — the connection string of a policy with Send permission. With the
thingsboardpolicy, paste the same string as for uplink. - Downlink topic name — enter
downlinktopic.
- Downlink connection string — the connection string of a policy with Send permission. With the
- Click Apply changes.
Encoder used in this guide (TBEL and JavaScript):
/** Encoder **/
// Publish the Rule Engine message as the message body.var result = { // Payload content type: JSON, TEXT, or BINARY (Base64). contentType: 'JSON', data: JSON.stringify(msg), metadata: { // Required. Becomes the message's To property // and the custom property deviceId. deviceId: metadata.deviceName }};
return result;To check the encoder, click Test encoder function. Message type is already ATTRIBUTES_UPDATED. Set Message to {"temperatureUploadFrequency":60} and deviceName in Metadata to 8F4A2C6D, if they differ, then click Test. The Output shows:
{ "contentType": "JSON", "data": "{\"temperatureUploadFrequency\":60}", "metadata": { "deviceId": "8F4A2C6D" }}To adapt:
- Another envelope — build
datain the structure your consumer expects, for example{ "device": metadata.deviceName, "config": msg }. - Routing properties — add keys to
metadata, for exampletype: 'config'. Subscription filter rules on the downlink topic can route on these custom properties. - Other message types — branch on
msgType, for example to handleRPC_CALL_FROM_SERVER_TO_DEVICEwithmsg.methodandmsg.params. See Rule Engine message types.
Configure the Root Rule Chain
Section titled “Configure the Root Rule Chain”The encoder reads deviceName from the message metadata, so the rule chain first adds the device name.
- Go to Data processing ⇾ Rule chains and open the Root Rule Chain.
- From the Enrichment section, drag an originator fields node onto the canvas.
- Enter a Name (for example,
Retrieve device name) and map the source fields:- Name ⇾ deviceName
- Add mapped originator fields to ⇾ Metadata
- Click Add.
- Connect the message type switch node to the originator fields node with the Attributes Updated relation.
- From the Action section, drag an integration downlink node onto the canvas.
- Enter a Name (for example,
Downlink to Azure Service Bus), select your Azure Service Bus integration, and click Add. - Connect the originator fields node to the integration downlink node with the Success relation.
- Click Apply changes.
Test Downlink
Section titled “Test Downlink”- Go to Devices & assets ⇾ Devices, select 8F4A2C6D, and open the Attributes tab.
- Select Shared attributes and click +.
- Set Key to
temperatureUploadFrequency, Type to Integer, Value to60, and click Add. ThingsBoard publishes the downlink.
Verify the Downlink
Section titled “Verify the Downlink”- Integration events — the integration’s Events tab shows a Downlink event with
deviceId,payload({"temperatureUploadFrequency":60}), andproperties. - Service Bus Explorer — open
downlinktopic, click Service Bus Explorer, and select the subscriptionS2. Select Peek Mode and click Peek from start. Select the message to see its body; the Message Properties tab showsToand thedeviceIdproperty.
Peek Mode leaves the message in the subscription. Receive Mode with ReceiveAndDelete removes it.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause | Fix |
|---|---|---|
| Check connection passes, but no uplinks arrive | Check connection does not connect to Service Bus. The namespace, topic, subscription, or key is wrong, or the policy lacks Listen. | Compare the names with the Azure portal. Copy the connection string again from a policy with Listen. |
| Same, from a private network | Outbound port 5671 is blocked. |
Open TCP 5671 to *.servicebus.windows.net, or use a Remote Integration. |
| Messages go to another consumer | Another application reads the same subscription. | Create a dedicated subscription for ThingsBoard. |
| Topics are not available | The namespace is on the Basic tier. | Upgrade the namespace to Standard or Premium. |
| Device not created | deviceName is empty, or Allow create devices or assets is off. |
Check Out in the converter events and the integration settings. |
| Message lost after a converter error | The integration removes every processed message, even when decoding fails. | Check Error events in the converter, fix the decoder, and resend the message. |
| Downlink event with an error | Wrong Downlink connection string or Downlink topic name, or the policy lacks Send. | Compare the topic name with the Azure portal. Use a policy with Send. |
| No downlink is sent | The rule chain does not reach the integration downlink node, or the encoder does not set metadata.deviceId. |
Check the Root Rule Chain wiring. Check Out in the downlink converter events for deviceId. |
| Downlink sent, nothing in the downlink subscription | The downlink topic had no subscription when the message arrived, or a subscription filter rejected it. | Create the subscription before you trigger the downlink. Check its filter rules. |
To read debug events, open the integration or converter, click Events, and select an event: In is the received data, Out is the converter result, and Error holds the error text.
See Also
Section titled “See Also”- Integrations overview — how integrations, converters, uplinks, and downlinks fit together.
- Uplink data converter — decoder inputs, output format, and scripting patterns.
- Downlink data converter — encoder reference.
- Remote Integration — run the integration outside the ThingsBoard cluster.
- TBEL — built-in functions and syntax for converter scripts.
- Service Bus queues, topics, and subscriptions — messaging model and subscription filters.
- Service Bus Explorer — send, peek, and receive messages in the Azure portal.
Was this helpful?