IoT Widget Contribution Guide
Welcome to ThingsBoard IoT Hub. This guide walks you through contributing a widget that end users can install on their ThingsBoard instance in a single click.
A widget contribution is a single JSON file that you export from ThingsBoard and upload through IoT Hub. When a user clicks Install on your widget, the platform imports it directly into their widget library where they can drop it onto any dashboard.
Before You Begin
Section titled “Before You Begin”Create a free Creator account on the ThingsBoard Creator Portal to start publishing your items.
How Users Install Your Widget
Section titled “How Users Install Your Widget”When a user installs your widget from IoT Hub:
- The platform downloads your widget JSON file.
- The widget is imported into the user’s Widget Library under a new widget bundle.
- The user can drop the widget onto any dashboard and configure data keys, targets, and styling as usual.
Your widget is self-contained — its HTML template, CSS, controller script, settings form, and default configuration all live inside the JSON. The end user does not need to install any dependencies or run any code outside ThingsBoard.
Quick Start
Section titled “Quick Start”- In your ThingsBoard instance, build and test your widget in the Widget Library editor.
- Export it as a JSON file — see Export the widget.
- Go to IoT Hub → + Add new item. A four-step wizard walks you through the rest:
- Upload — upload your exported JSON. The platform recognizes it as a widget automatically and pre-fills several fields.
- Listing — fill in the listing metadata (see Fill in the listing). Name, Image, Description, and Tags are pre-filled from the JSON; Categories, Use Cases, and the supported ThingsBoard version must be selected manually.
- Readme — write the long-form widget documentation in Markdown (see Readme content).
- Review & Submit — verify everything and submit the version for review.
The sections below are a complete reference for each step.
Export the Widget
Section titled “Export the Widget”- Open Resources → Widget Library in your ThingsBoard instance.
- Locate your widget in the list.
- In the row’s action cell, click the Export widget button.
- Save the resulting
.jsonfile — this is your upload file.
The exported file is a complete widget type definition and requires no further editing to be valid. If you want to override auto-derived fields (description, image, tags), you can edit the JSON directly before uploading.
Widget JSON Structure
Section titled “Widget JSON Structure”A valid widget file is a JSON object with the following structure:
{ "fqn": "john_doe.air_quality_card", "name": "Air quality index card", "description": "Displays the latest air quality index telemetry in a scalable rectangle card.", "image": "tb-image;/api/images/system/air_quality_index_card_system_widget_image.png", "tags": ["weather", "environment", "air", "aqi"], "deprecated": false, "descriptor": { "type": "latest", "sizeX": 3, "sizeY": 3, "templateHtml": "...", "templateCss": "...", "controllerScript": "...", "settingsForm": [], "dataKeySettingsForm": [], "defaultConfig": "{...}", "resources": [] }, "resources": [ { "link": "/api/images/system/air_quality_index_card_system_widget_image.png", "title": "Air quality index card system widget image", "type": "IMAGE", "mediaType": "image/png", "fileName": "air_quality_index_card_system_widget_image.png", "data": "iVBORw0KGgoAAAANS..." } ]}Set the Widget FQN
Section titled “Set the Widget FQN”Every widget published to IoT Hub must use a namespaced fqn in the form nickname.widget_fqn, where nickname is your own identifier — a personal handle (e.g. john_doe) or a company name (e.g. thingsboard). This keeps your widget unique across the marketplace and prevents widget name collisions with other contributors’ widgets.
The ThingsBoard widget editor does not allow setting a custom namespace prefix in the UI — the exported JSON will contain only the plain widget name (e.g. air_quality_card). After exporting, open the .json file and prepend your nickname:
{ "fqn": "john_doe.air_quality_card", ...}Pick one nickname and reuse it for every widget you publish.
Required Fields
Section titled “Required Fields”| Field | Type | Description |
|---|---|---|
fqn | string | Fully qualified name — a unique identifier across the widget library, in the form nickname.widget_fqn (e.g. john_doe.air_quality_card or acme.air_quality_card). Lowercase and underscores recommended. See Set the widget FQN |
name | string | Human-readable widget name (e.g. Air quality index card) |
descriptor | object | Widget configuration — must include a type field |
descriptor.type | string | One of timeseries, latest, rpc, alarm, static |
Optional Fields
Section titled “Optional Fields”| Field | Type | Description |
|---|---|---|
description | string | One-sentence description (max 512 chars). Shown on browse cards |
image | string | Preview image: data URI, /api/images/... reference (resolved from resources), external URL, or raw base64 |
tags | string[] | Free-form keywords used for search |
deprecated | boolean | Mark true to indicate the widget is deprecated |
resources | array | Embedded resources — images, external CDN scripts (e.g. ECharts), or ThingsBoard extensions. Populated automatically by ThingsBoard export |
Descriptor Fields
Section titled “Descriptor Fields”The descriptor object holds the widget’s visual and runtime definition. ThingsBoard populates all of these during export — you typically don’t need to hand-edit them.
| Field | Description |
|---|---|
type | Widget type (required) |
sizeX, sizeY | Default size in grid units |
templateHtml | Angular template HTML |
templateCss | CSS styles |
controllerScript | JavaScript controller code |
settingsForm | Form schema for widget settings |
dataKeySettingsForm | Form schema for data key configuration |
settingsDirective | Angular directive for settings UI |
dataKeySettingsDirective | Angular directive for data key settings |
defaultConfig | JSON string of default widget configuration |
hasBasicMode | Whether widget supports basic configuration mode |
basicModeDirective | Angular directive for basic mode UI |
resources | Embedded resources (images, external scripts) |
Fill in the Listing
Section titled “Fill in the Listing”The Listing step of the upload wizard collects the fields shown on the browse card and detail page. Name, Image, Description, and Tags are autofilled from your JSON; everything else you set here. Version and changelog are set per upload — see Versioning and checksum.
Listing Fields
Section titled “Listing Fields”| Field | Required | Source | Notes |
|---|---|---|---|
| Name | yes | name in JSON | Editable |
| Image | yes | image + resources in JSON | Editable — drop a new image to override |
| Description | yes | description in JSON | Editable, max 512 chars |
| Categories | yes | Manual | Pick from Widget categories |
| Use Cases | yes | Manual | Pick from Use cases |
| Supported ThingsBoard version | no | Manual | Min (≥) and optional max (<) version |
| Professional Edition | no | Manual | Toggle if the widget requires PE |
| Tags | no | tags in JSON | Editable |
Widget Categories
Section titled “Widget Categories”Pick one or more categories that describe what your widget is. Allowed values: Cards & Info, Charts & Graphs, Controls, Gauges & Indicators, Input Forms, Maps & Location, SCADA, Tables & Lists.
Use Cases
Section titled “Use Cases”Pick one or more IoT domains where your widget is useful. These are shared across the whole marketplace so users browsing by use case will see your widget alongside matching devices and dashboards.
Allowed values: Air Quality Monitoring, Asset Tracking, Cold Chain, Drones, Environment Monitoring, Fleet Tracking, Health Care, Industrial Automation, Predictive Maintenance, Robotics, SCADA, Smart Building, Smart City, Smart Energy, Smart Farming, Smart Home, Smart Metering, Smart Office, Smart Retail, Solar Monitoring, Tank Level Monitoring, Waste Management.
Preview Image
Section titled “Preview Image”The preview image is shown on browse cards and the widget’s detail page. A good preview image is critical — it’s the single biggest driver of whether users click on your widget.
There are two ways to set it:
- From the widget JSON — exports from ThingsBoard already embed a preview image, so it works out of the box.
- From the upload UI — in the Listing step of the wizard, drop a new file to override whatever came from the JSON.
Best practices.
- Use PNG for clean screenshots and diagrams
- Capture the widget in a realistic state (with actual data, not placeholder values)
- Crop tightly to the widget — avoid surrounding dashboard chrome
- Target 400–800 px wide; the file itself should be well under 200 KB
- Ensure the widget is legible at small card sizes
Readme Content
Section titled “Readme Content”The Readme step of the upload wizard collects the long-form widget documentation — what the widget displays, data keys, configuration, value ranges — shown on your widget’s detail page. It is written in standard Markdown.
A good readme always includes:
- What the widget displays — one or two sentences
- Data keys — exactly which telemetry or attribute keys the widget expects, including their types
- Configuration — notable settings the user can adjust
- Value ranges — for color-coded widgets, document every range and its color
Example:
## Air quality index card
Displays the latest air quality index (AQI) telemetry in a scalable rectangle card.
### Features
- Color-coded value ranges (Good / Moderate / Unhealthy / Hazardous)- Configurable icon with range-based coloring- Auto-scaling layout- Last update timestamp
### Data keys
- **air** (timeseries) — Air Quality Index value (0–500)
### AQI ranges
| Range | Level | Color ||---------|--------------------|---------|| 0–50 | Good | Green || 50–100 | Moderate | Yellow || 100–150 | Unhealthy (sensitive) | Orange || 150–200 | Unhealthy | Red || 200–300 | Very Unhealthy | Purple || 300+ | Hazardous | Maroon |Versioning and Checksum
Section titled “Versioning and Checksum”Each widget version is identified by a semver string (e.g. 1.0.0) plus a changelog entry, bumped every time you upload a changed JSON, and an SHA-256 checksum computed from:
fqnnamedescriptor(the entire descriptor object as JSON)
This means:
- Changing HTML, CSS, JS, or any descriptor field → checksum changes → you must bump the version
- Changing only
description,image, ortags→ checksum does not change (metadata-only update) - Same version + different checksum = the system detects a mismatch and rejects the update
Always bump the version when uploading a changed widget JSON.
Pre-Upload Checklist
Section titled “Pre-Upload Checklist”Widget JSON
Section titled “Widget JSON”Listing
Section titled “Listing”Readme
Section titled “Readme”Content Quality
Section titled “Content Quality”Writing the Changelog
Section titled “Writing the Changelog”When you upload a new version, pair the version bump with a changelog entry — a short note that tells users exactly what changed since the previous version, so they can decide whether, and how, to upgrade.
Document What’s New
Section titled “Document What’s New”Summarize what changed since the previous version: new features, bug fixes, breaking changes, and any migration notes users need to know.
Group your entry under these headings, and include only the ones that apply:
| Heading | What goes here |
|---|---|
| New features | New capabilities, configuration options, or behavior added in this version |
| Bug fixes | Defects corrected since the previous version — describe the symptom users saw, not the internal cause |
| Breaking changes | Anything that changes existing behavior in a way that can disrupt an installed copy — renamed keys, removed options, changed defaults |
| Migration notes | The concrete steps an existing user must take to move from the previous version to this one |
Write for the User
Section titled “Write for the User”- Lead with the user impact. Describe what the user can now do, or what no longer breaks — not how you implemented it.
- Be specific. Name the exact keys, fields, settings, or outputs that changed. “Renamed the output key from
temptotemperature” is actionable; “improved naming” is not. - One change per bullet. Keep each item to a single, scannable line.
- Flag breaking changes loudly. If an upgrade can disrupt an installed copy, say so explicitly and pair it with a migration note.
Pair every entry with a semantic version bump — patch (1.0.1) for fixes, minor (1.1.0) for backward-compatible features, major (2.0.0) for breaking changes.
Changelog Example
Section titled “Changelog Example”## 2.0.0
### Breaking changes- Renamed the output key from `temp` to `temperature` to match the ThingsBoard telemetry convention.
### Migration notes- Update any dashboards, alarm rules, or downstream calculated fields that read the `temp` key to read `temperature` instead.
### New features- Added an optional `humidity` argument; when present, the formula now also computes a `dewPoint` output.
### Bug fixes- Fixed missing output when the input telemetry arrived as a string instead of a number.After You Submit
Section titled “After You Submit”Once you complete the upload wizard and click Submit, your version enters the IoT Hub review queue. The ThingsBoard team checks every submission before it goes live.
Tracking Your Submission
Section titled “Tracking Your Submission”To see the current status of your submission, open the Creator Portal and go to Items. Find your item in the list and click the Manage Versions icon in its row. The Versions page lists every version you have uploaded with a Status column that updates in real time.
| Status | Meaning |
|---|---|
| Pending Review | Your version is in the review queue and has not been evaluated yet |
| Approved | Your version passed review and is now live on IoT Hub |
| Rejected | Your version did not pass review — see the reviewer comment for details |
What Reviewers Check
Section titled “What Reviewers Check”Reviewers verify that the submission meets the same criteria as the Pre-Upload Checklist: the widget JSON is valid and imports cleanly, the FQN is correctly namespaced, and the listing and readme give users enough context to evaluate and use the widget.
If Your Submission Is Rejected
Section titled “If Your Submission Is Rejected”The Status column will show Rejected. Open the version details to read the reviewer’s comment, which explains specifically what needs to be fixed.
To resubmit:
- Fix the reported issues in your local package.
- Return to Items → Manage Versions for your item.
- Click + Upload new version and complete the wizard with the corrected package.
See Also
Section titled “See Also”- Widgets — how end users discover and install a widget
Was this helpful?