Skip to content

Cookie preferences

We use cookies for our own analytics, to see how our campaigns perform and, if you allow it, to load content from other services such as the Google site search. We never sell your data. Necessary cookies keep the site working and cannot be switched off. See our Cookie Policy for details and our Privacy Policy for how we handle personal data.

Security, load balancing and remembering your cookie choice.

Show us which pages people read, how they find the site and where they get stuck, so we can improve it (Google Analytics, Microsoft Clarity).

Show us which of our ad campaigns bring visitors to the site and remember the campaign or partner link you arrived from (Google Ads, LinkedIn, Meta, partner program). We do not use these cookies to build advertising profiles.

Load the site search from Google when you use it. Google sets its own cookies and shows ads in the search results.

© 2026 The ThingsBoard Authors
22.6k Try for free

ThingsBoard Cloud

Choose your data region

Your data stays in the region you choose, for residency and compliance. No credit card required.

Rather run it yourself? Install on your own servers

Apache Pulsar Integration

Apache Pulsar Integration connects ThingsBoard to an Apache Pulsar cluster. ThingsBoard subscribes to the topics you configure and receives messages in batches. An uplink data converter transforms each message into device or asset data, including telemetry and attributes.

Use Apache Pulsar Integration when:

  • Devices or your applications already publish data to Pulsar topics, self-hosted or on a managed service such as StreamNative Cloud.
  • You want that data in ThingsBoard dashboards and the Rule Engine without a separate bridge service.

The integration is uplink-only: it does not publish messages to Pulsar.

  1. Receive data. A producer publishes a message to a Pulsar topic. The integration consumes the topic through a named subscription and receives messages in batches.
  2. Decode the payload. The uplink converter decodes each message and returns the device name, telemetry, and attributes.
  3. Process the message. ThingsBoard processes the converted data through the Rule Engine. If Allow create devices or assets is enabled, ThingsBoard creates the device on its first message.
  4. Acknowledge the batch. After processing a batch, the integration acknowledges all its messages to Pulsar, including messages the converter failed to decode. Pulsar does not redeliver them.
  • Access to ThingsBoard Cloud with integrations enabled for your tenant.
  • Permission to create integrations and data converters.
  • A Pulsar broker that ThingsBoard can reach. To start a local test broker, see Set Up Pulsar.
  • For a secured broker: a JWT token for a role that may consume from the topic.

Start a standalone broker in Docker. A standalone broker runs all Pulsar components in one container and creates topics on first use. With a managed service, skip this step and take the service URL and token from your provider.

Terminal window
docker run -d --name pulsar -p 6650:6650 -p 8081:8080 apachepulsar/pulsar:latest bin/pulsar standalone --advertised-address localhost

The broker accepts clients on pulsar://localhost:6650. --advertised-address localhost lets clients on the host, such as ThingsBoard, reach the broker. The Pulsar HTTP API is mapped to port 8081, because self-hosted ThingsBoard uses 8080. The short topic name my-topic used in this guide resolves to persistent://public/default/my-topic.

Create the uplink converter, assign it to a new Apache Pulsar integration, and publish a test message.

The uplink converter receives each message as a byte array, resolves the target device, and returns its telemetry and attributes. Apache Pulsar Integration uses the Generic converter: the decoder is a TBEL or JavaScript script. For converter types and the full decoder reference, see Uplink data converter.

This guide uses the sample message that the Test decoder function dialog provides by default:

{
"deviceName": "Thermometer",
"deviceType": "thermostat",
"serialNumber": "SN-12345",
"temperature": 25.5
}
  1. Go to Integrations ⇾ Data converters and click + Add data converter ⇾ Create new converter.

  2. Converter type — keep Uplink.

  3. Integration type — select Apache Pulsar.

  4. Name — enter a name, for example Apache Pulsar Uplink Converter.

  5. Main decoding configuration — the editor opens with the default decoder below. It already handles this message format, so keep it. It takes deviceName and deviceType from the message, the time from ts (milliseconds) or timestamp (ISO 8601), stores the keys in attributeKeyList (here serialNumber) as attributes, and stores all other fields as telemetry. When the message has no time field, it uses the server time. The editor opens in TBEL; use the TBEL / JS toggle to switch to JavaScript.

    // Decode an uplink message from a buffer
    // payload - array of bytes
    // metadata - key/value object
    /** Decoder **/
    // decode payload to JSON
    var data = decodeToJson(payload);
    // --- Device name and type ---
    var deviceName = data.deviceName != null ? data.deviceName : 'Unknown Device';
    var deviceType = data.deviceType != null ? data.deviceType : 'default';
    // var customerName = 'Customer C';
    // var groupName = 'thermostat devices';

    To adapt:

    • Device name in another field — replace data.deviceName and data.deviceType, for example with data.deviceId.
    • Other device properties — add their keys to attributeKeyList, for example firmwareVersion.
    • Assets instead of devices — uncomment assetName and assetType and use them instead of deviceName and deviceType.
    • Customer or group — uncomment customerName or groupName to assign the device to a customer or an entity group.
    • Update-only keys — in Advanced decoding parameters, add keys to the Update only keys list to store them only when their value changes, for example serialNumber.
  6. Click Test decoder function and check the result (see Test the Decoder).

  7. Click Add.

Decoder Inputs

The decoder signature is function decoder(payload, metadata): object | object[].

Variable Type Content
payload byte array The message body, unchanged. Binary formats arrive intact.
metadata {[key: string]: string} integrationName and the key–value pairs from the integration’s Metadata field.

The integration does not pass the topic, message key, or message properties to the decoder. To tell sources apart, put the information into the message, or create one integration per topic with its own Metadata.

Test the Decoder

Click Test decoder function below the editor. The Payload already holds the sample message. Click Test. The Output panel shows:

{
"deviceName": "Thermometer",
"deviceType": "thermostat",
"attributes": {
"serialNumber": "SN-12345"
},
"telemetry": {
"ts": 1792072084561,
"values": {
"temperature": 25.5
}
}
}

The message has no time field, so ts is the time of the test.

  1. Go to Integrations ⇾ Integrations and click + Add integration.
  2. Basic settings:
    • Integration type — select Apache Pulsar.
    • Name — enter a name, for example Apache Pulsar integration.
    • Enable integration and Allow create devices or assets — keep both on, so the device is created on its first message.
    • Click Next.
  3. Uplink data converter:
    • Click Select existing and choose Apache Pulsar Uplink Converter.
    • Alternatively, click Create new to write a decoder here.
    • Click Next.
  4. Connection:
    • Service URL — replace pulsar://YOUR_PULSAR_DOMAIN:6650 with pulsar://localhost:6650.
    • Topics and Subscription name — keep my-topic and my-subscription.
    • Credentials type — keep Anonymous for the local broker. For a secured broker, select Security token and paste the token.
    • Leave the other parameters at their defaults. See Connection Settings for details.
  5. Click Add.
Parameter Description
Service URL Broker address: pulsar://host:6650, or pulsar+ssl://host:6651 for TLS. With TLS, the integration does not verify the broker certificate. Required.
Topics Topics to consume, separated by commas without spaces. A short name resolves to persistent://public/default/<name>; for another tenant or namespace, enter the full name. Required.
Subscription name Name of the Pulsar subscription. Pulsar stores the read position per subscription, so the integration resumes from the same position after a restart. Required.
Max number of messages Maximum number of messages in one batch. Default: 1000.
Max number of bytes Maximum size of one batch, in bytes. Default: 10485760 (10 MB).
Timeout in milliseconds Maximum time to wait for a batch to fill. When it expires, the integration processes the messages received so far. Default: 100.
Credentials type Anonymous — no authentication. Security token — JWT authentication with the token in the Token field.
Execute remotely Runs the integration as a separate process outside the ThingsBoard cluster. ThingsBoard generates an Integration key and Integration secret for it. See Remote Integration.

Advanced settings

Parameter Description
Description Free-text description.
Metadata Key–value pairs added to the metadata of every message from this integration.

The subscription is Exclusive: only one consumer may use it. Give each integration that reads the same topic its own Subscription name.

Publish a message to my-topic, then confirm that ThingsBoard decoded it and created the device.

Create the integration first. A new subscription starts from the latest message, so it skips messages published before it was created. After that, Pulsar keeps unread messages for the subscription while the integration is offline.

Publish the sample message. The pulsar-client commands read it from a file, because the --messages option splits text at commas.

Terminal window
echo '{"deviceName":"Thermometer","deviceType":"thermostat","serialNumber":"SN-12345","temperature":25.5}' | \
docker exec -i pulsar sh -c 'cat > /tmp/msg.json && bin/pulsar-client produce my-topic -f /tmp/msg.json'
  • Integration events — go to Integrations ⇾ Integrations, open the integration, and click the Events tab. The uplink appears with status OK. The integration records the message body as Base64.
  • Converter events — open Apache Pulsar Uplink Converter in Integrations ⇾ Data converters and click the Events tab. In shows the message, Out shows the decoded result, and Metadata shows the integration name.
  • Device — go to Devices & assets ⇾ Devices. The integration has created Thermometer with type thermostat. Open it and check temperature on the Latest telemetry tab and serialNumber on the Attributes tab.
Symptom Cause Fix
“Host must be in the public network.” under Service URL The server does not allow integrations to connect to private addresses, for example on ThingsBoard Cloud. Use a public broker address, or a Remote Integration.
Integration does not start Wrong Service URL, the broker is down, or a firewall blocks the port. Check the URL scheme and port (pulsar://…:6650 or pulsar+ssl://…:6651) and that the broker accepts connections from the ThingsBoard host.
Same, on a secured broker The token is missing, expired, or its role may not consume from the topic. Select Security token and paste a valid token. Check the role’s permissions on the namespace.
Same, with a second integration on the topic Both use the same Subscription name, and the subscription allows one consumer. Give each integration its own Subscription name.
No messages received The producer writes to another topic, or the messages were published before the subscription was created. Check the full topic name, including tenant and namespace. Publish a new message.
Only the first topic works Topics contains spaces after the commas. Separate the topics with commas only.
Device not created Allow create devices or assets is off, or deviceName is empty. Turn the option on. Check Out in the converter events for deviceName.
Decoder error The message is not JSON, or a field is missing. Open the converter’s Events tab and read the Error column. The failed message is already acknowledged, so publish a corrected one.

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.