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

AWS Kinesis Integration

AWS Kinesis Integration connects ThingsBoard to Amazon Kinesis Data Streams. ThingsBoard reads every shard of a stream with the Kinesis Client Library (KCL). An uplink data converter transforms each record into device or asset data, including telemetry and attributes. ThingsBoard can also write downlink records to a Kinesis stream.

Use AWS Kinesis Integration when:

  • Devices, AWS IoT rules, or backend services already write data to a Kinesis data stream.
  • One stream carries data for many devices: the converter resolves each device from the record.
  • You need to send commands or events back to AWS through a stream.
  1. Receive data. A producer writes a record to the stream. The integration reads each shard and stores its read position (checkpoint) in an Amazon DynamoDB table.
  2. Decode the payload. The uplink converter receives the record data and its partition key, identifies the device or asset, and extracts attributes and telemetry.
  3. Process the message. ThingsBoard processes the converted data through the Rule Engine. If Allow create devices or assets is enabled, ThingsBoard creates an entity that does not exist yet.
  4. Send downlink data (optional). The Rule Engine passes a message to the integration. The downlink converter encodes it and names the target stream and partition key. The integration writes the record with the Kinesis Producer Library (KPL).
  • Access to ThingsBoard Cloud with integrations enabled for your tenant.
  • Permission to create integrations and data converters, and to edit rule chains for downlink.
  • An AWS account on a paid plan, with permission to create Kinesis data streams, IAM users, and IAM policies. Kinesis Data Streams is not available on the AWS Free plan.
  • The AWS CLI version 2, configured with aws configure for the Region you use, or AWS CloudShell in the AWS console, where the CLI is already configured for the console Region. This guide uses the CLI to create the streams and send test records.

Create two streams and an IAM user whose access key the integration uses.

This guide uses the stream my-thingsboard for uplink and tb-test-downlink for downlink. Create both in the same Region:

Terminal window
aws kinesis create-stream --stream-name my-thingsboard --shard-count 1
aws kinesis create-stream --stream-name tb-test-downlink --shard-count 1

On success, the commands print nothing. With --shard-count, each stream uses provisioned capacity with one shard.

Wait until both streams are active. Each command returns without output when StreamStatus is ACTIVE, usually within a minute:

Terminal window
aws kinesis wait stream-exists --stream-name my-thingsboard
aws kinesis wait stream-exists --stream-name tb-test-downlink

To check a stream, read its status, capacity mode, and shard count:

Terminal window
aws kinesis describe-stream-summary --stream-name my-thingsboard \
--query 'StreamDescriptionSummary.[StreamStatus,StreamModeDetails.StreamMode,OpenShardCount]'

The output lists ACTIVE, PROVISIONED, and 1.

Besides Kinesis, the integration uses Amazon DynamoDB and Amazon CloudWatch. KCL creates three DynamoDB tables named after the Application name of the integration (by default, the stream name): a lease table with checkpoints, <name>-CoordinatorState, and <name>-WorkerMetricStats. KCL and KPL also publish metrics to CloudWatch.

  1. Create the user. In the AWS console, open IAM ⇾ IAM users and click Create user.

    • Specify user details — enter a name, for example thingsboard-kinesis. Leave Provide user access to the AWS Management Console off: the integration needs only an access key.
    • Set permissions — select no group and no policy. The user gets only the policy from step 3.
    • Review and create — click Create user.
  2. The page of the new user opens. On the Permissions tab, click Add permissions ⇾ Create inline policy.

  3. In the Policy editor, switch to JSON and replace the content with the policy below. Replace REGION and ACCOUNT_ID with your Region and AWS account ID. Click Next, enter a Policy name, for example thingsboard-kinesis-policy, and click Create policy.

    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Sid": "ReadUplinkStream",
    "Effect": "Allow",
    "Action": [
    "kinesis:DescribeStream",
    "kinesis:DescribeStreamSummary",
    "kinesis:GetRecords",
    "kinesis:GetShardIterator",
    "kinesis:ListShards"
    ],
    "Resource": "arn:aws:kinesis:REGION:ACCOUNT_ID:stream/my-thingsboard"
    },
  4. Open the Security credentials tab and click Create access key. Select Application running outside AWS and click Next. AWS recommends temporary credentials instead; the integration needs an access key, so continue.

  5. Optionally, enter a Description tag value, for example ThingsBoard Kinesis integration, and click Create access key.

  6. On Retrieve access keys, copy the Access key and the Secret access key, or click Download .csv file. AWS shows the secret only once. Then click Done.

Create the uplink converter, assign it to a new AWS Kinesis integration, and write a test record.

The uplink converter receives the data of each record as a byte array, resolves the target device, and returns its telemetry and attributes. AWS Kinesis 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.

Kinesis does not define a record format. This guide uses the sample record 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 AWS Kinesis.

  4. Name — enter a name, for example AWS Kinesis Uplink Converter.

  5. Main decoding configuration — the editor opens with the default decoder below. It already handles this record format, so keep it. It takes deviceName and deviceType from the record, 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 record 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.
    • Device name from the partition key — if producers use the device ID as the partition key, use metadata.partitionKey.
    • 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.
  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 record data, exactly as the producer wrote it. The AWS CLI and SDKs Base64-encode data only in transit; the decoder receives the original bytes.
metadata {[key: string]: string} partitionKey and sequenceNumber of the record. Also integrationName and the key–value pairs from the integration’s Metadata field.

For field renaming, nested values, and non-JSON payloads, see Common scripting patterns.

Test the Decoder

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

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

The record 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 AWS Kinesis.
    • Name — enter a name, for example AWS Kinesis integration.
    • Enable integration and Allow create devices or assets — keep both on, so the device is created on its first record.
    • Click Next.
  3. Uplink data converter:
    • Click Select existing and choose AWS Kinesis Uplink Converter.
    • Alternatively, click Create new to write a decoder here.
    • Click Next.
  4. Downlink data converter:
  5. Connection:
    • Stream name — my-thingsboard.
    • Region — the code of the Region where you created the streams, for example eu-north-1.
    • Initial position in stream — select Latest.
    • Access Key Id and Secret Access Key — paste the access key of the IAM user.
    • Leave the other parameters at their defaults. See Connection Settings for details.
  6. Click Add.
Parameter Description
Stream name Stream the integration reads. Required.
Region AWS Region code of the stream, for example eu-north-1, not the Region name shown in the console. Required. The DynamoDB tables, CloudWatch metrics, and downlink stream use the same Region.
Initial position in stream Where to start reading a shard that has no checkpoint yet. Required. Latest reads only records written after the integration starts. Trim horizon reads from the oldest record still retained in the stream. At timestamp is not supported: the integration fails to start with Invalid InitialPosition: AT_TIMESTAMP.
Use credentials from the Amazon EC2 Instance Metadata Service Takes credentials from the IAM role of the EC2 instance that runs ThingsBoard or the remote integration. Hides Access Key Id and Secret Access Key. Off by default.
Access Key Id and Secret Access Key Access key of the IAM user. Required unless the previous option is on.
Use Consumers with Enhanced Fan-Out Reads through an enhanced fan-out consumer with dedicated read throughput, at extra AWS cost. Off by default, so the integration polls the shards. Turning it on hides Max records and Request timeout in seconds.
Max records Polling only. Maximum number of records per GetRecords request, 1–10000. Default: 10000.
Request timeout in seconds Polling only. Timeout of a GetRecords request. Default: 30.
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 Default Description
Application name Stream name KCL application name. It names the DynamoDB tables that keep the checkpoints. Integrations with the same name share these tables and split the shards between them; use different names for integrations that must each read every record.
Description — Free-text description.
Metadata — Key–value pairs added to the metadata of every message from this integration.

Write a record to the stream, then confirm that ThingsBoard decoded it and created the device.

Run aws kinesis put-record. The --cli-binary-format raw-in-base64-out option makes AWS CLI version 2 send --data as plain text:

Terminal window
aws kinesis put-record \
--stream-name my-thingsboard \
--partition-key Thermometer \
--cli-binary-format raw-in-base64-out \
--data '{"deviceName":"Thermometer","deviceType":"thermostat","serialNumber":"SN-12345","temperature":25.5}'

The command prints the ShardId and SequenceNumber of the new record. The integration reads it within a few seconds.

With Latest, the integration skips records written before it started reading. Write the record after the integration is created. If no uplink arrives, write the record again.

  • 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 shard ID, sequence number, partition key, and payload.
  • Converter events — open AWS Kinesis Uplink Converter in Integrations ⇾ Data converters and click the Events tab. In shows the record data, Out shows the decoded result, and Metadata shows the partition key, sequence number, and integration name.
  • Device — go to Devices & assets ⇾ Devices. The integration has created Thermometer with type thermostat. Open it and check temperature = 25.5 on the Latest telemetry tab and serialNumber on the Attributes tab.

ThingsBoard writes a downlink record when the Rule Engine routes a message to the integration — for example, after a shared attribute update. The target stream and partition key come from streamName and partitionKey in the downlink converter’s output metadata. The stream must be in the integration’s Region.

The downlink converter turns a Rule Engine message into a Kinesis record. For the full encoder reference, see Downlink data converter.

Add a downlink converter to the integration. The encoder returns:

Field Required Description
contentType Yes JSON, TEXT, or BINARY (a Base64-encoded string).
data Yes Record data.
metadata.streamName Yes Target stream.
metadata.partitionKey Yes Partition key. Records with the same key go to the same shard, in order.
  1. Open the integration in Integrations ⇾ Integrations and click Toggle edit mode (pencil icon).
  2. In the Downlink data converter field, click Create new. The Downlink converter type and AWS Kinesis integration type are preselected.
  3. Enter a name, for example AWS Kinesis Downlink Converter.
  4. In Main encoding configuration, replace the default encoder with the one below.
  5. To record downlink events, click the debug icon next to the name, select All messages, and click Apply.
  6. Click Add, then Apply changes.

Encoder used in this guide (TBEL and JavaScript):

/** Encoder **/
// Write the Rule Engine message data as the record data.
var result = {
contentType: "JSON",
data: JSON.stringify(msg),
metadata: {
// Target stream.
streamName: "tb-test-downlink",
// One partition key per device keeps its records in order.
// The originator fields node adds deviceName to the metadata.
partitionKey: metadata.deviceName
}
};
return result;

To adapt:

  • Other stream — change streamName. The IAM policy must allow kinesis:PutRecords on that stream.
  • Selected fields — build data from the fields you need, for example JSON.stringify({ interval: msg.temperatureUploadFrequency }).
  • Other message types — branch on msgType, for example RPC_CALL_FROM_SERVER_TO_DEVICE.

Attribute update messages carry no device name in their metadata. An originator fields node adds it, so the encoder can use it as the partition key.

  1. Go to Data processing ⇾ Rule chains and open the Root Rule Chain.
  2. From the Enrichment section, drag an originator fields node onto the canvas. Enter a Name (for example, Add device name). Under Originator fields mapping, map Name to the target key deviceName. Keep Add mapped originator fields to set to Metadata, and click Add.
  3. From the Action section, drag an integration downlink node onto the canvas. Enter a Name (for example, Downlink to AWS Kinesis), select your AWS Kinesis integration, and click Add.
  4. Connect the message type switch node to the originator fields node with the Attributes Updated relation.
  5. Connect the originator fields node to the integration downlink node with the Success relation.
  6. Click Apply changes.
  1. Go to Devices & assets ⇾ Devices, open Thermometer, and select the Attributes tab.
  2. Select Shared attributes and click +.
  3. Set Key to temperatureUploadFrequency, Type to Integer, Value to 60, and click Add. ThingsBoard writes the downlink record.
  • Converter events — open the downlink converter’s Events tab. In shows the Rule Engine message, and Out shows the encoded data with streamName and partitionKey = Thermometer in metadata.

  • Integration events — the integration’s Events tab shows a Downlink event with the stream name, partition key, and payload.

  • AWS — read the downlink stream from its oldest record. The command gets a shard iterator and passes it to get-records:

    Terminal window
    ITER=$(aws kinesis get-shard-iterator \
    --stream-name tb-test-downlink \
    --shard-id shardId-000000000000 \
    --shard-iterator-type TRIM_HORIZON \
    --query ShardIterator --output text)
    aws kinesis get-records --shard-iterator "$ITER"

    A shard iterator expires after 5 minutes. If Records is empty, run aws kinesis get-records --shard-iterator with the returned NextShardIterator until the record appears. The record has PartitionKey = Thermometer and Base64-encoded Data:

    {
    "Records": [
    {
    "SequenceNumber": "49679318713549456377638275380422332354075930242739863554",
    "ApproximateArrivalTimestamp": "2026-10-16T14:28:39.979000+00:00",
    "Data": "eyJ0ZW1wZXJhdHVyZVVwbG9hZEZyZXF1ZW5jeSI6NjB9",
    "PartitionKey": "Thermometer"
    }
    ],
    "MillisBehindLatest": 0
    }

    Decode Data to get the payload {"temperatureUploadFrequency":60}:

    Terminal window
    echo 'eyJ0ZW1wZXJhdHVyZVVwbG9hZEZyZXF1ZW5jeSI6NjB9' | base64 --decode

Delete the test resources when you finish, because AWS bills the streams for every shard-hour.

  1. In ThingsBoard, turn off Enable integration for the integration, or delete it. A running integration creates the DynamoDB tables again.

  2. Delete the streams and the DynamoDB tables. Use your Application name instead of my-thingsboard in the table names if you set one.

    Terminal window
    aws kinesis delete-stream --stream-name my-thingsboard
    aws kinesis delete-stream --stream-name tb-test-downlink
    aws dynamodb delete-table --table-name my-thingsboard
    aws dynamodb delete-table --table-name my-thingsboard-CoordinatorState
    aws dynamodb delete-table --table-name my-thingsboard-WorkerMetricStats
  3. Delete the IAM user. Its access keys and inline policy go first:

    Terminal window
    for k in $(aws iam list-access-keys --user-name thingsboard-kinesis \
    --query 'AccessKeyMetadata[].AccessKeyId' --output text); do
    aws iam delete-access-key --user-name thingsboard-kinesis --access-key-id "$k"
    done
    aws iam delete-user-policy --user-name thingsboard-kinesis --policy-name thingsboard-kinesis-policy
    aws iam delete-user --user-name thingsboard-kinesis
  4. Check that nothing is left. list-streams and list-tables print [], and get-user fails with NoSuchEntity:

    Terminal window
    aws kinesis list-streams --query 'StreamNames'
    aws dynamodb list-tables --query 'TableNames'
    aws iam get-user --user-name thingsboard-kinesis
Symptom Cause Fix
No uplinks and no errors The stream name or Region is wrong, or the record was written before the integration started with Latest. Check Stream name and Region. Write a new record.
Integration does not start, Invalid InitialPosition: AT_TIMESTAMP At timestamp is selected. Select Latest or Trim horizon.
AccessDeniedException in the logs or events The IAM policy lacks a Kinesis, DynamoDB, or CloudWatch action. Compare the policy with Create IAM Credentials. Check the table names when you use a custom Application name.
Old records are not read after switching to Trim horizon Checkpoints from the earlier run already exist. Set a new Application name.
Only some records arrive Another integration or KCL application with the same Application name reads the stream and takes some shards. Give each integration its own Application name.
Records processed twice after a restart The integration saves checkpoints on a graceful stop. After an unexpected stop, it resumes from the last saved checkpoint. Deduplicate in the Rule Engine where it matters, for example by sequenceNumber.
Decoder error The record data is not valid JSON. Open the converter’s Events tab and check In. Adapt the decoder to the producer’s format.
Device not created Allow create devices or assets is off. Turn the option on in the integration.
Device named Unknown Device appears The record has no deviceName field, so the decoder uses its default name. Read the device name from your field in the decoder. See To adapt in Create the Uplink Data Converter.
Downlink record has partition key null or ${partitionKey} The message metadata has no deviceName, so this guide’s encoder sets partitionKey to null (TBEL) or omits it (JavaScript, the placeholder is not replaced). The same applies to streamName. Add the originator fields node from Configure the Root Rule Chain, or set both keys in the encoder.
Downlink not written The rule chain does not reach the integration downlink node, or the IAM policy denies kinesis:PutRecords on the target stream. Check the Attributes Updated and Success relations and the policy.

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.