Skip to content
NEW AI Solution Creator — get a working IoT prototype in 10 minutes
Stand with Ukraine flag

The Things Stack Community Integration

The Things Stack Community integration connects ThingsBoard to The Things Network (TTN) — the world’s largest public LoRaWAN network — over MQTT. ThingsBoard subscribes to the TTN MQTT API, receives uplink messages from your LoRaWAN devices, decodes the payload via the uplink converter, and stores the result as ThingsBoard telemetry and attributes. Downlink is optional: when configured, ThingsBoard encodes Rule Engine messages via the downlink converter and publishes them back to TTN, which delivers them to the device.

Use this integration when your devices connect to the public The Things Network rather than a private The Things Industries tenant. For private TTI connectivity, see the The Things Stack Industries integration.

Before creating the integration, ensure:

  • You have access to ThingsBoard PE or ThingsBoard Cloud with integration functionality enabled for your tenant.
  • You have permissions to create integrations and data converters.
  • You have a The Things Network account with at least one registered application and device.
  • At least one device is registered in your TTN application and is sending uplinks. If you have not registered a device yet, follow the Register a Device step below.
  1. Log in to The Things Stack Console.
  2. Go to Applications tab, and click Add application.
  3. Enter Application ID — e.g. my-thingsboard.
  4. Click Create application.

The API key authenticates ThingsBoard against the TTN MQTT broker. It is used as the password for the MQTT connection.

  1. Open your application in the TTN Console.
  2. In the left sidebar, go to API keys and click + Add API key.
  3. Enter a name — e.g. ThingsBoard.
  4. Grant the following rights:
    • Read application traffic (uplink)
    • Write downlink application traffic
  5. Click Create API key.
  1. In the left sidebar, go to End devices and click + Register end device.
  2. On the Register end device page, configure the End device type:
    • Under Input method, select Enter end device specifics manually.
    • Frequency plan — e.g. Europe 863-870 MHz (SF9 for RX2 - recommended).
    • LoRaWAN version — e.g. LoRaWAN Specification 1.0.0.
    • Regional Parameters version — e.g. TS002 Technical Specification 1.0.0.
  3. Click Show advanced activation, LoRaWAN class and cluster settings and set Activation mode to Activation by personalization (ABP).
  4. Scroll down to Provisioning information and fill in the required fields:
    • DevEUI — click Generate. This becomes the device identifier in ThingsBoard.
    • Device address — click Generate.
    • AppSKey — click Generate. Application session key used to encrypt the payload.
    • NwkSKey — click Generate. Network session key used for MAC-layer integrity.
    • End device ID — e.g. thermostat-a. This value is used later to route downlink messages.
  5. Click Register end device.

The uplink converter receives each TTN uplink message, decodes the LoRaWAN payload, and returns a structured object that ThingsBoard uses to create or update a device and store its telemetry and attributes.

If your device is in the built-in catalog, use the Library tab instead of writing a decoder — see Converters library for over 100 ready-made decoders.

For the full decoder function reference — all input parameters and output fields — see Uplink data converter.

  1. Go to Integrations center ⇾ Data converters.
  2. Click + Add data converter ⇾ Create new converter.

In the Add data converter dialog:

  1. Converter type — leave Uplink (selected by default).
  2. Integration type — in the search field, enter The Things Stack and select The Things Stack Community from the list.
  3. Name — enter a converter name, for example TTN Uplink Converter.
  4. Configure main decoding parameters:
    • Device name - the default value Device $eui names each ThingsBoard device using the DevEUI from the uplink message (e.g. Device 0004A30B001C4523). On the first uplink ThingsBoard creates the device; on subsequent uplinks it updates the existing one. Change this pattern if you want a different naming scheme.
    • The default decoder is pre-filled. Leave it unchanged for this guide.
      By default the editor opens in TBEL; use the TBEL / JS toggle (upper right) to switch languages.
    • /**
      * Decodes the incoming payload and returns a structured object containing telemetry data and attributes.
      *
      * @param {byte[]} input - The raw payload received as an array of bytes.
      * @returns {Object} output - The structured output with decoded telemetry and attributes.
      */
      function decodePayload(input) {
      // Initialize the output object with empty attributes and telemetry for clarity.
      var result = { attributes: {}, telemetry: {}};
      // Detect input type and normalize to byte array
      var bytes;
      if (metadata.payloadFormat == 'JSON') {
      // payloadFormat is 'JSON' when The Things Network payload formatters are configured on the application or device level.
      // In that case, decoded_payload is a JSON object produced by your formatter.
      // This template assumes the formatter returns { "bytes": [...] } with the raw byte array.
      // If your formatter returns pre-decoded values in a different structure,
      // update this section to extract the values directly from 'parsed' instead.
      var parsed = decodeToJson(input);
      if (parsed.bytes == null) {
      throw new Error("Payload formatter output does not contain a 'bytes' field. " +
      "Update this decoder to match your formatter's output structure.");
      }
      bytes = parsed.bytes;
      } else {
      // payloadFormat is 'BINARY' when no payload formatter is configured — raw bytes from frm_payload are passed directly.
      bytes = input;
      }
      // Decode serial number (SN) from the first 4 bytes of the payload.
      // Press '?' icon in the top right corner to learn more about built in helper functions and capabilities.
      result.attributes.sn = parseBytesToInt(bytes, 0, 4);
      // Extract the timestamp from metadata (represented in milliseconds).
      var timestamp = metadata.ts; // ts is the timestamp parsed from the incoming message's time, or returns the current time if it cannot be parsed.
      // Combine the timestamp with decoded values and add it to the telemetry.
      result.telemetry = {
      ts: timestamp,
      values: {
      // Decode battery level from the 5th byte of the payload.
      battery: parseBytesToInt(bytes, 4, 1),
      // Decode temperature from the 6th and 7th bytes of the payload (divided by 100).
      temperature: parseBytesToInt(bytes, 5, 2) / 100.0,
      // Decode saturation from the 8th byte of the payload.
      saturation: parseBytesToInt(bytes, 7, 1)
      }
      };
      // Return the fully constructed output object.
      return result;
      // Same logic, less code:
      // return {
      // attributes: {
      // sn: parseBytesToInt(bytes, 0, 4)
      // },
      // telemetry: {
      // ts: convertDateToTimestamp(extractDateFromMetadata()),
      // values: {
      // battery: parseBytesToInt(bytes, 4, 1),
      // temperature: parseBytesToInt(bytes, 5, 2) / 100.0,
      // saturation: parseBytesToInt(bytes, 7, 1)
      // }
      // }
      // };
      }
      var result = decodePayload(payload);
      // Uncomment this code block to overwrite values set in the main configuration window. Useful if you extract device/asset/customer/group names from the payload;
      // result.type = 'DEVICE'; // Entity type allows you to choose type of created entity. Can be 'DEVICE' or 'ASSET'.
      // result.name = 'Temperature Sensor'; // Device or asset name (the value must be unique)
      // result.profile = 'IndustrialSensorProfile'; // Device or asset profile name.
      // result.customer = 'MyCustomer'; // If customer is not null - created entity will be assigned to customer with such name.
      // result.group = 'SensorsGroup'; // If group is not null - created entity will be added to the entity group with such name.
      // Return the final result object.
      return result;
  5. Review advanced decoding parameters — pre-populated for The Things Stack Community; leave defaults unless your setup differs.

    These parameters control TTN network metadata — signal quality, location, and LoRa settings that ThingsBoard extracts automatically from each uplink message. The decoder script above controls device sensor data — the fields written to result.attributes and result.telemetry.values. You do not need to add your sensor field names to the Telemetry or Attributes lists here.

    The default telemetry keys extracted from TTN messages include: fCnt, data, decoded, latitude, longitude, altitude, rssi, snr, channel.

    The default attribute keys include: eui, devAddr, fPort, bandwidth, spreadingFactor, codeRate, frequency, brandId, modelId, hardwareVersion, firmwareVersion, attributes, tenantId.

    The Update only keys list controls which attribute values are saved to the database only when they differ from the previously stored value — useful for slowly changing attributes like spreadingFactor or firmwareVersion.

  6. Click Add.

The decoder handles both input formats automatically: raw bytes when no TTN payload formatter is configured, and pre-parsed JSON when one is. No changes to the decoder are needed for either case.

What the Converter Receives

ThingsBoard passes two variables to the decoder function:

VariableTypeDescription
payloadbyte arrayThe LoRaWAN payload bytes. For BINARY format — raw bytes from frm_payload. For JSON format — bytes of the serialized decoded_payload object produced by the TTN formatter.
metadataobjectKey-value map populated from the TTN uplink MQTT message.

Key metadata fields available in the decoder:

FieldDescription
metadata.payloadFormat'BINARY' or 'JSON' — use this to branch your decoding logic
metadata.tsUplink timestamp in milliseconds, parsed from the TTN received_at field; falls back to server time if the field is absent or unparseable
metadata.euiDevEUI of the sending device, e.g. 0004A30B001C4523
metadata.devAddrDevice address assigned by the network
metadata.fPortLoRaWAN frame port number
metadata.spreadingFactorSpreading factor of the uplink transmission
metadata.rssiReceived signal strength indicator (dBm)
metadata.snrSignal-to-noise ratio (dB)

Example: BINARY Payload Decoded

The decoder assumes a fixed binary payload structure. It reads byte ranges using parseBytesToInt(input, offset, length) and produces:

BytesFieldOutput typeExpressionNotes
0–3snattributeparseBytesToInt(bytes, 0, 4)Device serial number
4batterytelemetryparseBytesToInt(bytes, 4, 1)Battery level
5–6temperaturetelemetryparseBytesToInt(bytes, 5, 2) / 100.0Raw value ÷ 100
7saturationtelemetryparseBytesToInt(bytes, 7, 1)Saturation level

Example payload (hex):

00BC614E5F092950

Example output:

{
"attributes": { "sn": 12345678 },
"telemetry": {
"ts": 1690000000000,
"values": {
"battery": 95,
"temperature": 23.45,
"saturation": 80
}
}
}

Adapting the Converter

  • Different device name — change the Device name pattern in Main decoding configuration (e.g. replace Device $eui with $deviceId or a fixed string).
  • Different byte layout — adjust the offset and length in each parseBytesToInt() call to match your payload structure.
  • Different field names — rename battery, temperature, or saturation to match your data model; add or remove fields as needed.
  • TTN payload formatter — if your TTN application or device profile has a JavaScript payload formatter configured, ThingsBoard receives the formatter’s output as a JSON object (payloadFormat == 'JSON'). The decoder maps all formatter fields directly into telemetry. If you need only a subset of fields, replace values: decoded with an explicit mapping, for example: values: { temperature: decoded.temperature, humidity: decoded.humidity }.
  • Additional attributes — add more keys to result.attributes (e.g. result.attributes.firmwareVersion = decoded.fw).
  1. Go to Integrations center ⇾ Integrations and click + Add integration.
  2. Basic settings:
    • Select The Things Stack Community as the integration type.
    • Enter a Name for the integration, or keep the default The Things Stack Community integration.
    • Enable integration and Allow create devices or assets are enabled by default.
    • Click Next.
  3. Uplink data converter:
    • Click Select existing and choose the TTN Uplink Converter created in the previous step.
    • Alternatively, click Create new to define the decoder inline, or use Library to load a vendor-provided preset.
    • Click Next.
  4. Downlink data converter:
    • Click Skip — the downlink converter is only needed for sending commands to devices and can be added later.
  5. Connection settings:
    • Host type — leave Region selected.
    • Region — enter the identifier of the TTN cluster where your application is registered (e.g. eu1). ThingsBoard constructs the broker hostname as {region}.cloud.thethings.network.
    • Port8883.
    • Credentials:
      • Username — your TTN Application ID with @ttn appended (e.g. my-thingsboard@ttn).
      • Password — the API key generated in the create an API access key step.
    • Enable SSL and Use API v3 are on by default — leave them enabled.
    Read more about each parameter in connection settings.
  6. Optionally click Check connection — the wizard advances to a verification step showing Connected when successful.
  7. Click Add to complete the integration setup.

Host type

ValueDescription
RegionConnect to a standard public TTN cluster. Enter the Region identifier (e.g. eu1, nam1, au1) — ThingsBoard constructs the broker host as {region}.cloud.thethings.network.
CustomSpecify a fully custom broker hostname — use this for private or self-hosted The Things Stack deployments.

Port

ValueDescription
8883TLS-encrypted MQTT. Required when Enable SSL is on. Default and recommended for all public TTN clusters.
1883Unencrypted MQTT. Only use this for local or private deployments where TLS is not available.

Credentials

ParameterValue
UsernameYour TTN Application ID followed by @ttn (e.g. my-thingsboard@ttn). The Application ID is the identifier you set when creating the application — not your TTN account username.
PasswordThe API key generated in your TTN application.

Enable SSL

Encrypts the MQTT connection using TLS. Enabled by default and required for all connections to public TTN clusters (port 8883). Disable only when connecting to a local deployment on port 1883.

Use API v3

Controls the MQTT topic structure. Leave enabled for all current TTN deployments.

SettingUplink topic filterDescription
Enabled (default)v3/+/devices/+/upTTN Stack v3 topic format — required for all public TTN clusters
Disabled+/devices/+/upLegacy v2 topic format — only for older self-hosted deployments

Topic filters

Defines which MQTT topics ThingsBoard subscribes to for uplink messages. Set automatically based on Use API v3 — leave the default unless you need to restrict the subscription to a specific application or device.

FieldDescription
TopicMQTT topic filter. + matches a single topic level. Default: v3/+/devices/+/up (all devices across all applications accessible with the API key).
QoSQuality of service level: 0 — at most once; 1 — at least once (may deliver duplicates); 2 — exactly once.

Execute remotely

When enabled, ThingsBoard generates an Integration key and Integration secret that let external services push messages into this integration via the ThingsBoard Integration API. Not needed for standard TTN MQTT connectivity.

Advanced settings

ParameterDefaultDescription
Protocol versionMQTT 3.1.1MQTT protocol version for the broker connection. Change to MQTT 5 only if required by your broker configuration.
Max bytes in message32368Maximum payload size in bytes. Messages exceeding this limit are silently dropped.
Connection timeout (sec)10Seconds ThingsBoard waits for a broker response before marking the connection as failed.
Downlink topic patternv3/{username}@ttn/devices/${devId}/down/pushMQTT topic used to publish downlink messages to TTN. {username} is the MQTT username configured above; ${devId} is resolved from metadata.devId in the downlink converter output.

After the integration is created, send a test uplink and confirm that ThingsBoard received the message, decoded it correctly, and provisioned the device.

Use the TTN console to simulate an uplink message and confirm that ThingsBoard receives and decodes it correctly.

  1. In the TTN Console, go to End devices and open thermostat-a — or the end device you registered earlier.
  2. Open the Messaging tab and click Simulate uplink.
  3. Leave FPort at its default value (1).
  4. In the Payload field, enter the test payload:
    00BC614E5F092950
  5. Click Simulate uplink. A Success — Uplink sent toast confirms the message was accepted by TTN.

This payload matches the byte layout from the uplink converter: sn = 12345678, battery = 95, temperature = 23.45, saturation = 80.

Go to Integrations center ⇾ Integrations, open The Things Stack Community integration, and click the Events tab. Each successfully processed uplink appears as a row with status OK.

To inspect converter processing, go to Integrations center ⇾ Data converters, click TTN Uplink Converter, and open its Events tab:

  • In — the raw TTN message passed to the decoder.
  • Out — the decoded result: attributes and telemetry values written to ThingsBoard.
  • Metadata — the integration name and MQTT topic associated with the message.

Go to Entities ⇾ Devices. ThingsBoard automatically provisions a new device named Device <DevEUI> (e.g. Device 70B3D57ED80054FE) on the first uplink from each end device. Open the device and click the Latest Telemetry tab — you should see temperature, battery, and saturation decoded by the converter, plus network metadata fields such as rssi, snr, and latitude extracted from the TTN message.

To send commands from ThingsBoard to TTN devices, configure the Rule Engine to trigger the downlink converter when a shared attribute is created or updated on the device.

Configure the Root Rule Chain to forward attribute changes to the TTN integration.

Two nodes are needed: an originator fields node that reads the TTN End device ID from the ThingsBoard device Label and puts it into message metadata, and an integration downlink node that sends the message to the integration.

  1. Open Rule Chains ⇾ Root Rule Chain and click the edit icon.
  2. In the node panel, search for originator fields and drag it onto the canvas.
  3. Configure the node:
    • Name — e.g. Retrieve device ID.
    • Under Originator fields mapping, set Source field to Label and Target key to devId.
    • Set Add mapped originator fields to to Metadata.
    • Click Add.
  4. In the node panel, search for integration downlink and drag it onto the canvas.
  5. Configure the node:
    • Name — e.g. Downlink to The Things Stack Community.
    • Integration — select The Things Stack Community integration.
    • Click Add.
  6. Connect the message type switch node to the originator fields node using the Post attributes and Attributes Updated relations.
  7. Connect the originator fields node to the integration downlink node using the Success relation.
  8. Click Apply changes.

The downlink converter receives a Rule Engine message and encodes it into a TTN-compatible downlink payload. The converter output must be a JSON object with the following structure:

{
"contentType": "JSON",
"data": "{\"downlinks\":[{\"f_port\":2,\"frm_payload\":\"e3Bvd2VyU3RhdGU9b259\",\"priority\":\"NORMAL\"}]}",
"metadata": {
"devId": "thermostat-a"
}
}
FieldDescription
contentTypeEncoding of the data field: TEXT, JSON, or BINARY.
dataThe TTN downlink payload serialized as a string. Must contain a downlinks array with f_port, frm_payload (base64-encoded bytes), and priority. See the TTN API documentation for the full field list.
metadata.devIdTTN End device ID of the target device (e.g. thermostat-a). The Originator fields node (configured in the next step) injects this value from the ThingsBoard device’s Label attribute.

For the full encoder function reference, see Downlink data converter.

Add the downlink converter to the existing integration:

  1. Go to Integrations center ⇾ Integrations and open the The Things Stack Community integration.
  2. Click the pencil icon to enter edit mode.
  3. In the Downlink data converter field, click Create new.
  4. Enter a name (e.g. TTN Downlink Converter), paste the encoder script below, and click Add.
  5. Click Apply changes to save the integration.
var devId = metadata.devId;
var data = {
downlinks: [{
f_port: 2,
confirmed: false,
frm_payload: btoa(msg),
priority: "NORMAL"
}]
};
var result = {
contentType: "JSON",
data: JSON.stringify(data),
metadata: {
devId: devId
}
};
return result;

The originator fields node injects metadata.devId from the ThingsBoard device’s Label attribute. The full Rule Engine message is serialized to JSON and base64-encoded into frm_payload.

To adapt this converter:

  • Different port — change f_port to match the LoRaWAN port your device listens on.
  • Confirmed downlink — set confirmed: true to request an acknowledgement from the device. Use with caution — unacknowledged confirmed frames consume retries and may delay subsequent messages.
  • Selective payload — the encoder sends the full message body. To send only a specific field, replace JSON.stringify(msg) with JSON.stringify({ key: msg.key }).
  • Different device routingmetadata.devId is populated by the Originator fields node from the device Label. If your ThingsBoard devices use a different attribute to store the TTN End device ID, update the Originator fields node mapping accordingly.

Trigger a downlink by adding a shared attribute to the ThingsBoard device provisioned during the uplink test:

  1. Go to Entities ⇾ Devices, open the device provisioned by the integration, and open the Attributes tab.
  2. Switch to Shared attributes and click +.
  3. Set the key (e.g. powerState) and a value (e.g. on).
  4. Click Add.

To verify the downlink was processed, go to Integrations center ⇾ Data converters, open TTN Downlink Converter, and click the Events tab. Click an event row to inspect:

  • In — the Rule Engine message received by the converter: msg contains the attribute payload; metadata.devId contains the TTN End device ID injected by the Originator fields node.
  • Out — the encoded output sent to TTN: a JSON downlinks array with frm_payload base64-encoded from the message body.

Go to the TTN Console, open End devices ⇾ thermostat-a (or your device), and click the Live data tab — the downlink event appears in the list.

This section covers the most common problems encountered when setting up and running the The Things Stack Community integration. Each entry describes the symptom, the most likely cause, and the steps to resolve it.

No Uplinks Received

SymptomCauseFix
No uplinks receivedWrong MQTT credentialsOpen the integration, click the pencil icon, go to the Connection step, and re-enter the credentials. The Username must be in the format {applicationId}@ttn (e.g. my-thingsboard@ttn) — not your TTN account username. The Password is the TTN API key.
No uplinks receivedTTN API key expired or revokedIn the TTN Console, open your application, go to API keys, and confirm the key is active. Create a new key with Read application traffic (uplink) right and update the integration password.
No uplinks receivedTTN API key missing required rightsThe API key must have the Read application traffic (uplink) right. Open the key in the TTN Console and confirm.
No uplinks receivedWrong cluster regionThe broker host is constructed as {region}.cloud.thethings.network. Confirm the Region field matches the cluster your TTN application is registered on — eu1, nam1, or au1. Open your TTN application in the Console and check the server address in the address bar.
No uplinks receivedSSL mismatchPort 8883 requires Enable SSL to be on. Port 1883 requires it to be off. Using port 8883 without SSL, or 1883 with SSL, causes a connection failure.
No uplinks receivedWrong topic filterWhen Use API v3 is on (default), the uplink topic must be v3/+/devices/+/up. When off, it must be +/devices/+/up. Open the integration in edit mode and check the Topic filters field.
Check connection passes but no uplinks arriveNo devices sending uplinksConfirm the end device is active and sending messages. In the TTN Console, open the device and click Live data — uplinks appear in real time.

Uplink Received but Device Not Created

SymptomCauseFix
Uplink received, no device in ThingsBoardAllow create devices or assets is disabledOpen the integration, click the pencil icon, and enable Allow create devices or assets in the Basic settings step.
Uplink received, no device in ThingsBoardConverter returns empty output or device name is unresolvedGo to Integrations center ⇾ Data converters, open the uplink converter, and click the Events tab. Inspect the Out panel of a recent event — confirm name is present and non-empty. If the Device $eui template is used, confirm metadata.eui is populated in the In panel.
Uplink received, converter shows errorTBEL or JavaScript exception in the decoderOpen the uplink converter Events tab, filter by Error, and inspect the stack trace. Common causes: incorrect byte offset, division by zero, or undefined variable.

Downlink Not Delivered

SymptomCauseFix
Downlink converter Events tab is empty — no events triggeredRule Chain misconfiguredIn the Root Rule Chain, confirm the message type switch node is connected to the Originator fields node via the Attributes Updated relation, and that the Originator fields node connects to the Integration Downlink node via Success.
Downlink converter triggered but metadata.devId is emptyThingsBoard device Label is not setOpen the device in Entities ⇾ Devices, click the pencil icon, and set the Label field to the TTN End device ID (e.g. thermostat-a). The Originator fields node reads the device Label and injects it into metadata.devId. Without it, the downlink topic cannot be resolved and no message is sent to TTN.
Downlink converter triggered, metadata.devId is set, but no downlink in TTNTTN API key missing downlink rightThe API key must have the Write downlink application traffic right. Open the key in the TTN Console and confirm, or create a new key and update the integration password.
Downlink converter triggered, output looks correct, TTN shows no downlinkWrong f_portThe device must be listening on the f_port specified in the downlink converter. Check the device’s firmware documentation and update f_port in the encoder if needed.
Downlink delivered to TTN but device does not respondconfirmed: true with no acknowledgementIf the downlink uses confirmed: true, the device must send an uplink to acknowledge. If the device is out of range or offline, confirmed frames are retried by TTN until the retry limit is reached, which delays subsequent messages. Switch to confirmed: false unless ACK tracking is required.

Connection Check Fails

SymptomCauseFix
”Connection refused”Wrong port or SSL settingConfirm port 8883 with SSL on, or port 1883 with SSL off.
”Connection timeout”Wrong cluster hostnameConfirm the Region is set correctly and the host resolves to {region}.cloud.thethings.network. Use Custom host type and enter the full hostname directly to rule out a region lookup issue.
”Unauthorized” or “Bad credentials”Invalid username or passwordRe-enter the username in {applicationId}@ttn format and paste a fresh API key as the password.
”Not authorized to subscribe”API key lacks uplink read rightCreate a new key with Read application traffic (uplink) and update the integration password.

How to Read Debug Events

  1. Go to Integrations center ⇾ Integrations, open The Things Stack Community integration, and click the Events tab.
  2. Click an event row to inspect:
  • In — the raw MQTT message received from TTN before processing.
  • Out — what the converter returned: device name, attributes, and telemetry values passed to ThingsBoard.
  • Error — error text and stack trace, if processing failed.

Enable Debug mode on the integration to capture all raw input/output events. Starting from ThingsBoard 3.9, full debug events are stored only during the first hour — afterward, only error events are retained. Disable debug mode once the issue is identified.