# Welcome

Overview of the Heisenware platform, architecture, core concepts, and key terminology.

**Heisenware is an industrial application platform.** You build software visually and deploy it to production without writing boilerplate or setting up infrastructure. Underneath sits a distributed architecture, so your Apps scale from a single machine to a whole plant. When you need to go deeper, you reach the code and configuration directly.

## The platform at a glance

Three core components cover the entire application lifecycle:

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><strong>App Manager</strong></td><td>Admin dashboard to create and manage Apps, members, and integrations.</td><td><a href="/pages/a3pKpLtQeKEuF5NsR0LS">/pages/a3pKpLtQeKEuF5NsR0LS</a></td><td><a href="/files/cr5RVc6CpAqDWMy4FUQ0">/files/cr5RVc6CpAqDWMy4FUQ0</a></td></tr><tr><td><strong>App Builder</strong></td><td>Visual programming interface to build and test custom software applications.</td><td><a href="/pages/WUtWGgiYZu97iJRNGPpc">/pages/WUtWGgiYZu97iJRNGPpc</a></td><td><a href="/files/6W3rvaGXraXKqGjtxV3W">/files/6W3rvaGXraXKqGjtxV3W</a></td></tr><tr><td><strong>Production Apps</strong></td><td>The live, end-user-facing Apps created and run with Heisenware.</td><td><a href="/pages/eX9BSJ3DVEaP8Qjw36Rx">/pages/eX9BSJ3DVEaP8Qjw36Rx</a></td><td><a href="/files/rVOh6wx1SxKxyrdeykOc">/files/rVOh6wx1SxKxyrdeykOc</a></td></tr></tbody></table>

## Hosting and architecture

The [Heisenware architecture](/account/hosting-and-architecture) consists of the central platform and optional [Agents](/app-builder/build-backend/agents). Each account (tenant) runs in isolation and supports two deployment modes:

* **Cloud deployment**: The recommended way to use Heisenware. We host your Apps on [Hetzner](https://www.hetzner.com/) in Germany.
* **On-premises deployment**: You run the entire platform as a Docker application on your local servers or private cloud.

Whichever mode you choose, [Agents](/app-builder/build-backend/agents) bridge separated networks for you. For example, when you host the platform in a corporate data center (IT) and need to reach machines in a secured shopfloor network (OT), an Agent opens the secure tunnel.

## See it in action

Watch how to build and operate industrial apps in Heisenware.

{% embed url="<https://www.youtube.com/watch?v=MM4teGtbB7k>" %}

## Engineering philosophy and core concepts

Heisenware is a visual programming environment. A few engineering concepts, all kept visible and under your control, make it click.

### Transparency and flexibility

Heisenware keeps the underlying complexity visible and reachable. When you need custom logic, it is there.

* **Visual with full code access:** You build logic visually in the [Backend Builder](/app-builder/build-backend) and still reach developer tools directly, like JavaScript expressions for data transformation and YAML for configuration.
* **Extensible**: When the built-in [functions](/app-builder/build-backend/functions) fall short, you wrap your own code (Node.js, Python, C++) into Custom Extensions that become native functions.

### Object-oriented scalability

Heisenware uses an object-oriented model. You build logic once and instantiate it across an entire fleet of devices.

* **Classes (the blueprint)**: Reusable logic definitions, e.g. the [OPC UA client connector](/app-builder/build-backend/functions/connectors/opc-ua-client) or an [email connector](/app-builder/build-backend/functions/connectors/email).
* **Instances (the asset)**: Living, stateful copies of a class. You don't write code for machine A. You create an instance of the OPC UA client, name it `opcua-machine-a`, and give it the machine's IP and credentials.
* **Stateful context**: Member functions carry their own context, e.g. which server to use, so you pass no global variables.

### Native event-driven architecture

Industrial systems are asynchronous. Sensors spike, users click, and machines stop at unpredictable times. Heisenware Apps handle this natively.

* **Reactive logic**: [Backend flows](/app-builder/build-backend) do not run in a linear loop. They sit dormant until a specific trigger (an event) fires.
* **Event sources**: A trigger can be a user interaction (a UI event), a data change (e.g. a PLC tag update), or a system lifecycle event.
* **Non-blocking**: Your UI stays responsive while backend logic handles complex tasks asynchronously.

### Distributed connectivity

Heisenware closes the "OT vs. IT" network gap by treating local hardware as a first-class citizen of the cloud platform.

* **The bridge**: [Native Agents](/app-builder/build-backend/agents/native-agent) and [Docker Agents](/app-builder/build-backend/agents/docker-agent) securely connect local, private networks (OT/shopfloor) to the cloud without VPNs.
* **Local execution**: You push backend logic ([connectors](/app-builder/build-backend/functions/connectors)) to run locally on the edge device, and the platform treats these remote functions exactly like cloud functions.

### Unified data binding

Heisenware removes the "glue code" you would normally write to connect a frontend to a backend.

* **Direct linking**: In the [App Builder](/app-builder/overview), you connect a backend function's output straight to a frontend [widget's](/app-builder/build-frontend/widgets) property.
* **Reactive UI**: When backend data changes (e.g. a new sensor reading), the bound widget re-renders to reflect the new state.

<figure><img src="/files/5Tpl0IjrSzBi7C4d2SZC" alt=""><figcaption></figcaption></figure>

## Glossary

A quick-reference list of specific terms and concepts used across the Heisenware platform.

<table><thead><tr><th width="136.22772216796875">Term</th><th>Description</th></tr></thead><tbody><tr><td><strong>Account</strong></td><td>The top-level organizational container representing a tenant (e.g. <code>acme.heisenware.cloud</code>). It houses all workspaces, members, and shared resources.</td></tr><tr><td><a href="/pages/68iZO9IumCQHKTgtKl2A"><strong>Agent</strong></a></td><td>A local service (Native, Docker, or LXC) that executes backend logic at the edge, inside separated networks such as a secured shopfloor. It also tunnels data from local protocols (e.g. OPC UA, Modbus, S7) securely to the platform.</td></tr><tr><td><a href="/pages/eX9BSJ3DVEaP8Qjw36Rx"><strong>App</strong></a></td><td>A standalone progressive web app (PWA), built, tested, and deployed entirely within Heisenware.</td></tr><tr><td><a href="/pages/WUtWGgiYZu97iJRNGPpc"><strong>App Builder</strong></a></td><td>The visual development environment where members design, build, test, and deploy Apps.</td></tr><tr><td><a href="/pages/a3pKpLtQeKEuF5NsR0LS"><strong>App Manager</strong></a></td><td>The central administrative dashboard for managing accounts, workspaces, Apps, members, and inbound integrations.</td></tr><tr><td><a href="/pages/QcuiUnNwUVUEf6KYSm0k"><strong>Backend Builder</strong></a></td><td>The infinite canvas within the App Builder where members create event-driven business logic by wiring functions into reactive flows.</td></tr><tr><td><strong>Class</strong></td><td>A reusable logic definition, or blueprint, that you instantiate to create working copies.</td></tr><tr><td><strong>Code Adapter</strong></td><td>Developer-written code (Node.js, Python, C++, etc.) that wraps existing software libraries or algorithms so they integrate into Heisenware as Custom Extensions.</td></tr><tr><td><a href="/pages/b4tfHtSAX5IEEIoPUgSN"><strong>Connector</strong></a></td><td>A ready-made class for communicating with external systems and protocols, e.g. OPC UA, MQTT, databases, or email.</td></tr><tr><td><a href="/pages/81Mp6obNduXEYvTNjjS1"><strong>Custom Extension</strong></a></td><td>A containerized module (typically built via a Code Adapter) loaded into the platform to expand native functionality with custom, proprietary backend tools.</td></tr><tr><td><strong>Data Visualizer</strong></td><td>A tool for exploring your data directly. You view, filter, and visualize entries without building an App. Currently in beta.</td></tr><tr><td><strong>Deployment</strong></td><td>Publishing a specific version of an App, moving it from the App Builder environment to a live state accessible to users.</td></tr><tr><td><strong>Domain</strong></td><td>The unique identifier combining your account and workspace (e.g., <code>acme.default</code>) used for internal routing and API integrations.</td></tr><tr><td><strong>Event</strong></td><td>A specific occurrence, such as a user click, a data update, or a schedule interval, that initiates the execution of a flow in the backend.</td></tr><tr><td><a href="/pages/kQIuWBgas85Ggw96XGvq"><strong>Extension node</strong></a></td><td>A lightweight node (modifier, filter, recorder, or error handler) attached to a function to transform data, gate execution, record values, or handle errors within a flow.</td></tr><tr><td><a href="/pages/ExtZYf5KEiRmvVfHjuds"><strong>File Explorer</strong></a></td><td>The panel in the App Builder used to upload, store, and manage static assets and files (e.g. images, CSVs, PDF templates) for use in your Apps.</td></tr><tr><td><a href="/pages/5Q19JgoLcel9vA3B4Kz2"><strong>Filter</strong></a></td><td>An extension node that evaluates a boolean JavaScript expression to act as a logical gate, conditionally halting or allowing a data flow.</td></tr><tr><td><strong>Flow</strong></td><td>A reactive, event-driven sequence of connected functions that executes business logic.</td></tr><tr><td><a href="/pages/IgWS85MBrRz7MmiIXkqT"><strong>Frontend Builder</strong></a></td><td>The page-specific visual design canvas within the App Builder where members compose responsive user interfaces from widgets and static elements.</td></tr><tr><td><strong>Function</strong></td><td>An atomic, visual building block in the Backend Builder representing executable code that performs a specific task (e.g. database queries, API calls, hardware control).</td></tr><tr><td><a href="/pages/904pUlilAQkdiaOe6XOb"><strong>Function Explorer</strong></a></td><td>The structural repository panel in the App Builder containing all available functions, organized by categories like connectors, storage, utilities, and extensions.</td></tr><tr><td><strong>Instance</strong></td><td>A living, stateful copy of a class, configured for a specific asset. For example, an instance of the OPC UA client named <code>opcua-machine-a</code> holds one machine's IP and credentials.</td></tr><tr><td><strong>Integration</strong></td><td>A configured, authorized entry point that lets external systems, MQTT clients, or VRPC clients securely send data to a Heisenware workspace.</td></tr><tr><td><strong>JavaScript expression</strong></td><td>Standard JavaScript logic evaluated on the fly within modifiers or filters to perform calculations, condition checks, or array manipulations.</td></tr><tr><td><strong>JSONata</strong></td><td>A lightweight query and transformation language natively supported in Heisenware for efficiently restructuring JSON data payloads.</td></tr><tr><td><strong>Listener</strong></td><td>The input argument of a <a href="/pages/LlwGnU4Yk213ZPhr2t1a#callbacks">callback</a> function that monitors external systems or instances for events and processes incoming payloads.</td></tr><tr><td><strong>Member</strong></td><td>A developer, engineer, or administrator with access to the Heisenware platform to build and manage Apps (strictly distinct from a user).</td></tr><tr><td><a href="/pages/YtEGKytnifBFufwjxy3Y"><strong>Modifier</strong></a></td><td>An extension node that transforms or reshapes data on the fly as it passes from one function to the next within a flow.</td></tr><tr><td><a href="/pages/IRikNVUhOB7Z5kVtBgOC"><strong>Page Explorer</strong></a></td><td>The panel in the App Builder used to structure an App's hierarchy by creating, duplicating, and organizing pages and subpages, and to configure menus per screen size.</td></tr><tr><td><a href="/pages/avZz4jNnzxnhvzfxSZH2"><strong>PDF Template Editor</strong></a></td><td>The tool in the App Builder for designing PDF templates that the <code>fillTemplate</code> function populates with dynamic data at runtime.</td></tr><tr><td><strong>Property</strong></td><td>Anything about a widget that can change, including its value, scale, visibility, and color. Any property can be bound to backend logic to drive the UI dynamically.</td></tr><tr><td><strong>PWA (Progressive Web App)</strong></td><td>A modern web application standard that provides a native app-like experience (installable, responsive, offline-capable) directly from any web browser.</td></tr><tr><td><a href="/pages/FvBlSw7VIvVxI7ryxsDn"><strong>Subflow</strong></a></td><td>A reusable group of connected functions encapsulated as a single function for use in other flows.</td></tr><tr><td><a href="/pages/xgLUSDdUWfRVkPupilK2"><strong>Tag</strong></a></td><td>A named, point-in-time snapshot of an App's configuration (logic, UI, and bindings) that you can export, restore, or use as a template blueprint.</td></tr><tr><td><a href="/pages/y5JkCBhKRyGCtbadxAac"><strong>Theme Editor</strong></a></td><td>The tool in the App Builder for defining an App's colors, fonts, and visual styling, applied consistently across its pages and widgets.</td></tr><tr><td><strong>Trigger</strong></td><td>A function input or output configured to start flow execution when an event arrives, following the pattern on &#x3C;source> &#x3C;mode>, e.g. on input update.</td></tr><tr><td><strong>User</strong></td><td>An end-user who logs in or otherwise interacts with a live, published Heisenware App (strictly distinct from a member).</td></tr><tr><td><a href="https://vrpc.io/"><strong>VRPC</strong></a></td><td>The open-source, asynchronous communication protocol over MQTT that powers all distributed data exchange and remote function calls within the Heisenware ecosystem.</td></tr><tr><td><a href="/pages/HM2ZeE2nRRApl4lCtcuX"><strong>Widget</strong></a></td><td>An interactive or display-oriented visual component (e.g. a chart, button, or form) placed in the Frontend Builder to construct the user interface.</td></tr><tr><td><strong>Workspace</strong></td><td>A dedicated sub-container within an account used to securely isolate related Apps, databases, files, and members from one another.</td></tr><tr><td><strong>YAML</strong></td><td>A human-readable data serialization language used extensively in the Backend Builder for quickly configuring static function inputs and data structures.</td></tr></tbody></table>


# Release notes


# v92 — Hotel

12 July 2026

<div align="left"><figure><img src="/files/qU83EFTsccwtX85ioo0U" alt="" width="375"><figcaption></figcaption></figure></div>

## Features

* **Finalized** [**subflows**](/app-builder/build-backend/functions/subflows): Completed the core subflows feature within the [Backend Builder](/app-builder/build-backend).
* **Data Visualizer (beta)**: Introduced the Data Visualizer tool to let members inspect connected database tables and data entries directly without building an App.
* **Introduced the** [**timeline**](/app-builder/build-frontend/widgets/display-widgets/timeline) **widget**: Display chronological data series dynamically inside your Apps.
* **Introduced the** [**iframe**](/app-builder/build-frontend/widgets/display-widgets/iframe) **widget**: Cleanly embed external web content inside your frontend layouts.
* **Released the** [**Heidenhain DNC**](/app-builder/build-backend/functions/connectors/heidenhain-dnc) **Agent**: Run a native Heidenhain DNC Agent to establish direct edge connectivity with supported CNC systems.
* **Released the** [**LXC Agent**](/app-builder/build-backend/agents/lxc-agent-insys): Package your local connector system within an Insys-compatible LXC Agent container.

## Improvements

* **Restructured product documentation**: Completely rebuilt the [documentation](https://docs.heisenware.com/) to improve readability and user navigation.
* **Explicit data schema re-scanning**: Added an explicit data re-scan option for bound [widgets](/app-builder/build-frontend/widgets). A widget – such as a [data grid](/app-builder/build-frontend/widgets/display-widgets/data-grid) – now checks if its underlying data structure or keys have changed, and then automatically updates its properties and visual layout to match.
* **Overhauled** [**Page Explorer**](/app-builder/build-frontend/page-explorer): Integrated the navigation menu editor directly into the Page Explorer panel. You can configure the name, icon, and app bar title of each page using an edit icon next to the page name. Menu layouts can now vary based on screen size, using layouts like Bottom tabs only for mobile screens or Fixed left menu for large desktop monitors.
* **Fixed menu drawer**: Added a fixed-size left menu as a new navigation option in the [Page Explorer](/app-builder/build-frontend/page-explorer).
* **Independent** [**extension nodes**](/app-builder/build-backend/extension-nodes): Converted extensions – including modifiers, filters, recorders, and error handlers – into distinct visual nodes on the canvas.
* **Anti-node-collision ("snowplow")**: Implemented automated node separation in the [Backend Builder](/app-builder/build-backend) to prevent overlapping logic blocks.
* **Backend auto-formatting**: Introduced an auto-formatting layout tool for backend flows in the [Backend Builder](/app-builder/build-backend).
* **Event flow spotlight**: Added a visual spotlight effect to backend [functions](/app-builder/build-backend/functions) to clearly trace active event paths during live execution.
* **Visual data truncation**: Implemented automatic visual data truncation for large data payloads to keep the frontend responsive.
* **Custom** [**data list**](/app-builder/build-frontend/widgets/display-widgets/data-list) **spacing**: Added custom vertical spacing options in the data list widget configuration.
* **Enhanced** [**chart**](/app-builder/build-frontend/widgets/display-widgets/chart) **interaction**: Improved zoom and pan responsiveness for the chart widget.
* **Upgraded MQTT broker**: Updated and optimized the internal MQTT broker configuration to increase overall message resilience.
* **Application-wide client caching**: Implemented client-side caching to reduce browser reload times drastically for deployed [Production Apps](/production-apps/overview).

## Fixes

* **Initial backend state**: Fixed a synchronization issue where the correct backend state did not display immediately after account creation.
* **Alias persistence**: Fixed an issue where custom alias names did not save or persist correctly.
* **Widget highlighting**: Fixed intermittent visual bugs that broke selection and hover highlighting for [widgets](/app-builder/build-frontend/widgets) on the canvas.
* **Multi-monitor scaling**: Fixed a layout scaling bug in deployed [Production Apps](/production-apps/overview) when a browser window spans multiple monitors.


# v91 — Worth It

16 Mar 2026

<div align="left"><figure><img src="/files/tDo9LesKO2ennCE3jQq3" alt=""><figcaption></figcaption></figure></div>

## Features

* Manage professional licenses, subscriptions, and self-service payments through a Stripe integration in the Plan & Billing screen of the [App Manager](/app-manager/overview).
* Added support for multi-field configurations in the [timeseries database](/app-builder/build-backend/functions/storage/timeseries-database).
* Released a lightweight [Docker Agent](/app-builder/build-backend/agents/docker-agent) designed to run on resource-constrained edge devices and IoT gateways.
* Added new `Duration` and `Interval` helper objects for JavaScript expressions within the [modifier](/app-builder/build-backend/extension-nodes/modifier#javascript-expressions) extension node.

## Improvements

* Optimized [App Builder](/app-builder/overview) performance and decreased workspace load times, especially when reloading browser pages.

## Fixes

* Fixed canvas widget transformations when zooming on pages with extended height in the [Frontend Builder](/app-builder/build-frontend).
* Fixed an issue where [Production Apps](/production-apps/overview) performed incorrect automatic page switching after a new deployment.
* Resolved a race condition that created zombie subscriptions on the broker, improving overall platform performance.
* Fixed a CSS z-index layout bug that caused widgets to overflow the bottom navigation bar.
* Fixed event-style function subscription losses that occurred when an [Agent](/app-builder/build-backend/agents) encountered network reconnections.


# v90 — Grouped periodically

19 Feb 2026

<div align="left"><figure><img src="/files/AB9zC2NnuK8fr2qIyVl7" alt="" width="285"><figcaption></figcaption></figure></div>

## Features

* **Generic and nested widget grouping**: Added support for generic and fully nested widget grouping using the [dynamic group](/app-builder/build-frontend/widgets/dynamic-group) widget.
* **Data binding to groups**: Enabled high-level data binding for widget groups in the [dynamic group](/app-builder/build-frontend/widgets/dynamic-group#data-settings-data-bindings) configuration.
* **Introduced the** [**card**](/app-builder/build-frontend/widgets/display-widgets/card) **widget**: Display visually grouped components dynamically inside your Apps.
* **Multi-state** [**status lamp**](/app-builder/build-frontend/widgets/display-widgets/status-lamp): Improved the status lamp widget to support multiple states and a rectangular shape.
* **Configurable backgrounds for icons**: Improved the icon component in [Text, icons and images](/app-builder/build-frontend/text-icons-and-images) to support optional background shapes.
* **Runtime properties**: Added support for configuring multiple new properties at runtime across various [widgets](/app-builder/build-frontend/widgets).
* **Database audit logging**: Added database audit logging to the [relational database](/app-builder/build-backend/functions/storage/relational-database#audit-logging) connector.
* **Machine simulator option**: Added the machine simulator option to the [Process Simulations](/app-builder/build-backend/functions/extensions/process-simulations) extension.
* **AI assistant (beta)**: Released the first experimental version of the AI assistant.
* **Experimental subflows**: Released the first experimental support for [subflows](/app-builder/build-backend/functions/subflows).

## Improvements

* **UI interaction and performance**: Optimized user interface interactions and platform performance across the workspace.
* **Codebase health**: Cleaned up and consolidated the internal widget rendering factory.

## Fixes

* **On-premise system restarts**: Fixed system start behaviors to reliably restore [on-premise installations](/tutorials/on-premise-installation) after a power cycle.


# v89 — Look & feel

7 Dec 2025

<div align="left"><figure><img src="/files/SpjbLlRy8XLIJzNVQZsD" alt="" width="375"><figcaption></figcaption></figure></div>

## Features

* Redesigned the entire [App Builder](/app-builder/overview) user interface:
  * Upgraded the internal rendering engine to MUI.
  * Implemented numerous UI/UX enhancements to improve usability across the platform.
  * Added context-aware popup menus for configuring widget settings.
  * Added context-aware popup menus for configuring function input settings.
  * Enabled viewport navigation using WASD and QE keyboard controls in the Backend Builder.
* Added a card detail view option in the [data grid](/app-builder/build-frontend/widgets/display-widgets/data-grid) widget.
* Added a global settings menu in the [App Builder](/app-builder/overview) to customize workspace and editor behavior.
* Added support for placing annotations anywhere on the canvas in the [Backend Builder](/app-builder/build-backend).
* Added support for programmatically generating user invitation links inside your Apps using the [users](/app-builder/build-backend/functions/utilities/users) utility class.
* Released professional installation tools for [Native Agents](/app-builder/build-backend/agents/native-agent).
* Added the [cron](/app-builder/build-backend/functions/utilities/cron) utility class to schedule recurring tasks.
* Introduced the [Allen-Bradley](/app-builder/build-backend/functions/connectors/allen-bradley) PLC connector.
* Added the [stopwatch](/app-builder/build-backend/functions/utilities/stopwatch) utility class.
* Introduced the [GPIO Counter](/app-builder/build-backend/functions/connectors/gpio-counter) connector to count digital pulses and track cycle intervals with Raspberry Pi.

## Fixes

* The `createFolder` function of the [File I/O](/app-builder/build-backend/functions/connectors/file-i-o) connector now recursively creates directories and no longer fails if a directory already exists.
* Resolved multiple bugs and hardware incompatibilities in the [Zebra RFID IoT](/app-builder/build-backend/functions/connectors/zebra-rfid-iot) connector to fully support recent Zebra hardware releases.
* Fixed several user interface alignment and drag-and-drop inaccuracies inside the canvas.
* Resolved Google authentication failures occurring on self-built [Production Apps](/production-apps/overview).
* Improved performance and security hardening of the built-in [timeseries database](/app-builder/build-backend/functions/storage/timeseries-database).


# v88 — Almost forever

12 Oct 2025

<div align="left"><figure><img src="/files/PGl0bAxg9qy7L9fFWArc" alt="" width="285"><figcaption></figcaption></figure></div>

## Features

* Added table management, direct writes, and automatic downsampling to the [timeseries database](/app-builder/build-backend/functions/storage/timeseries-database).
* Configure photo resolution directly within the [photo](/app-builder/build-frontend/widgets/input-widgets/photo) widget.
* Introduced [Docker Extensions](/app-builder/build-backend/functions/extensions) to run custom code for your Apps, both in the cloud or on-premises. (Made the [Industrial Blockchain](/app-builder/build-backend/functions/extensions/industrial-blockchain), [Process Simulations](/app-builder/build-backend/functions/extensions/process-simulations), and [RAG AI](/app-builder/build-backend/functions/extensions/rag-ai) Docker Extensions.
* Added a single-command script for [on-premise installation](/tutorials/on-premise-installation).
* Released the [Docker Agent](/app-builder/build-backend/agents/docker-agent), which lets you run connectors on any hardware that supports Docker.
* The [upload](/app-builder/build-frontend/widgets/input-widgets/upload) widget now directly supports uploading photos.
* The [barcode / QR](/app-builder/build-frontend/widgets/input-widgets/barcode-qr) widget now supports scanning multiple barcodes sequentially without closing the camera preview.

## Fixes

* Fixed multi-file upload behavior in the [upload](/app-builder/build-frontend/widgets/input-widgets/upload) widget when utilizing buffer storage.
* Resolved a positioning discrepancy between the [App Builder](/app-builder/overview) preview and [Production Apps](/production-apps/overview) when using the Top Bar or Top Bar and Bottom Tabs in the [Page Explorer](/app-builder/build-frontend/page-explorer). Widgets in Production Apps no longer render too low on the y-axis.
* Fixed a bug where the `fontSize` property on the [button](/app-builder/build-frontend/widgets/trigger-widgets/button) did not apply correctly.
* Duplicating canvas sections now correctly clears all pre-existing widget connections.
* Fixed an issue where the `onJsonMessage` and `onStringMessage` events inside the [MQTT Client](/app-builder/build-backend/functions/connectors/mqtt-client) connector failed to trigger correctly when registered multiple times.
* Resolved a dependency issue with serial data transfer that caused the [Modbus](/app-builder/build-backend/functions/connectors/modbus) connector to crash on startup.
* Fixed a rendering bug in the [Backend Builder](/app-builder/build-backend) flow interface where the connection arrow was missing when linking event handlers to function inputs.
* Fixed an issue where the incorrect initial page loaded when an App used programmatic page switching.

## Changes

* Renamed the file widget to [upload](/app-builder/build-frontend/widgets/input-widgets/upload), and added new filtering categories including photo.
* Configured backend event flows to only activate when running in test mode.

## Breaking changes

* If your App uses a top bar or top bar and bottom tabs navigation layout, you may need to adjust your widget positions to align with the new layout rendering (see [Fixes](#fixes)).
* The `readXlsx` function in the [File I/O](/app-builder/build-backend/functions/connectors/file-i-o) connector no longer returns an object containing the sheet name as the sole key when processing a single sheet. It now returns the array of rows directly.


# v87 — Explained

28 Aug 2025

<div align="left"><figure><img src="/files/tPxL7AvRnUVj8oB26ZUj" alt="" width="375"><figcaption></figcaption></figure></div>

## Features

* Major documentation improvements on our [Product Docs](https://docs.heisenware.com/) portal.
* Added interactive, in-app onboarding to help new developers get started inside the [App Builder](/app-builder/overview).
* Redesigned and improved invitation emails sent to new users.
* Added enterprise-grade PKI (public-key infrastructure) security support for the [OPC UA Client](/app-builder/build-backend/functions/connectors/opc-ua-client) connector.
* Directly drag and drop backend [functions](/app-builder/build-backend/functions) onto widgets to connect them instantly.
* Expand [widgets](/app-builder/build-frontend/widgets) to full width on the canvas with a single click.
* Introduced the [Modbus](/app-builder/build-backend/functions/connectors/modbus) connector.
* Configure conditional runtime visibility for fields inside the [form](/app-builder/build-frontend/widgets/input-widgets/form) widget.
* Extract data from a [relational database](/app-builder/build-backend/functions/storage/relational-database) across multiple tables on the fly.
* Deregister users directly in [Users and access](/app-manager/users-and-access) inside the [App Manager](/app-manager/overview).
* Introduced the [SAP Digital Manufacturing](/app-builder/build-backend/functions/connectors/sap-digital-manufacturing) connector.

## Fixes

* Optimized [App Builder](/app-builder/overview) performance when designing very large Apps.
* Fixed the [text box](/app-builder/build-frontend/text-icons-and-images) component to always stay on top of other elements on the canvas while building.
* Prevents widgets from being dragged outside the canvas boundary in the Frontend Builder.
* Resolved access and permission issues with invite-only options in [Users and access](/app-manager/users-and-access).
* Fixed addressing issues when using dictionary variable names inside the [Siemens S7](/app-builder/build-backend/functions/connectors/siemens-s7) connector.


# v86 — Snapped

1 July 2025

<div align="left"><figure><img src="/files/gA1lOjiZ2vUWGngWU18A" alt="" width="375"><figcaption></figcaption></figure></div>

## Features

* Improved layout alignment with smart snaplines when designing in the Frontend Builder.
* Select and group multiple widgets simultaneously on the canvas.
* Added a [barcode generation](/app-builder/build-backend/functions/utilities/barcode-generation) utility to generate QR codes and barcodes.
* Configure asset label templates and print them directly using the [Label Printer](/app-builder/build-backend/functions/connectors/label-printer) connector.
* Standardized secure sign-up and sign-in URLs for [Production Apps](/production-apps/overview).
* Programmatically toggle edit mode and search queries on the [data list](/app-builder/build-frontend/widgets/display-widgets/data-list) widget.
* Exchange files generically between your Apps and a running [Agent](/app-builder/build-backend/agents).
* Automatically generate a version [tag](/app-builder/deploy-and-maintain) each time you deploy your App.

## Fixes

* Optimized caching routines to lower the memory consumption of running [Apps](/production-apps/overview).
* Improved performance and stability for the built-in [relational database](/app-builder/build-backend/functions/storage/relational-database).
* Fixed an issue where newly created widgets were not automatically selected.
* Fixed rendering issues that occurred when collapsing layout sections on the canvas.
* Sped up startup times and reduced memory footprints during whole-platform power-cycles.
* Improved screen scaling for [Production Apps](/production-apps/overview) and resolved a flickering issue on the [data grid](/app-builder/build-frontend/widgets/display-widgets/data-grid) widget.


# v85 — Safety net

1 June 2025

<div align="left"><figure><img src="/files/DVZr5qVfBW86RA9rIxLd" alt="" width="375"><figcaption></figcaption></figure></div>

## Features

* Added support for creating [tags](/app-builder/deploy-and-maintain) and sharing your Apps.
* The [Hydra MIP](/app-builder/build-backend/functions/connectors/hydra-mip) connector now supports PDM calls for Hydra 8.
* Added more [utility functions](/app-builder/build-backend/functions/utilities).
* Enabled alphanumerical sorting for your Apps, widgets, and items inside the [Function Explorer](/app-builder/build-backend/functions/function-explorer) and Frontend Builder.

## Fixes

* Fixed an issue in the [relational database](/app-builder/build-backend/functions/storage/relational-database) connector that prevented establishing multiple one-to-many associations on the same tables.
* Fixed the `onBrowserRefresh` event to trigger reliably inside the [App Builder](/app-builder/overview).
* Fixed an issue where [input widgets](/app-builder/build-frontend/widgets/input-widgets) lost focus while a user was typing.
* Optimized the performance of the underlying persistence infrastructure.


# v84 — Get in the flow

15 April 2025

<div align="left"><figure><img src="/files/hBRuOLmCsBUDxKgeDFKg" alt="" width="375"><figcaption></figcaption></figure></div>

## Features

* Redesigned the Backend Builder to use a flow-based visualization with nodes and edges/wires.
* Added support for the iPhone-specific `.heic` image format in the [upload](/app-builder/build-frontend/widgets/input-widgets/upload) and [photo](/app-builder/build-frontend/widgets/input-widgets/photo) widgets.
* Enabled clickable text links inside the [kanban](/app-builder/build-frontend/widgets/display-widgets/kanban) and [data grid](/app-builder/build-frontend/widgets/display-widgets/data-grid) widgets.
* Optimized rendering and layout scaling for [Production Apps](/production-apps/overview) across different devices and screens.
* Added an invite-only option in [Users and access](/app-manager/users-and-access) to manage access control for Apps.
* Introduced the [Hydra MIP](/app-builder/build-backend/functions/connectors/hydra-mip) connector.

## Fixes

* Fixed packaging issues for the Windows Agent.
* Fixed date values submitted from the [form](/app-builder/build-frontend/widgets/input-widgets/form) widget to always use the UTC timezone.
* Resolved PDF rendering issues on recent iOS devices.
* Fixed the onboarding flow to log users in automatically immediately after they verify their account from an email invitation.


# v83 — Beauty treatment

Oct 15, 2024

<div align="left"><figure><img src="/files/cLGsRQMqNHBAub8fN68K" alt="" width="175"><figcaption></figcaption></figure></div>

## Features

* Improved the visual style of the login form for [Production Apps](/production-apps/overview).
* Improved connection highlighting across the Backend Builder and Frontend Builder.
* Added Agent selection as a field type inside the [form](/app-builder/build-frontend/widgets/input-widgets/form) widget.
* Added the new [data tiles](/app-builder/build-frontend/widgets/display-widgets/data-tiles) widget.
* Expanded features and improved the overall usability of the [operating system (OS)](/app-builder/build-backend/functions/connectors/operating-system-os) connector.
* Added support for method calling and file I/O operations in the [OPC UA Client](/app-builder/build-backend/functions/connectors/opc-ua-client) connector.
* Enabled Docker container monitoring in the OS connector.
* Added the new [pie chart](/app-builder/build-frontend/widgets/display-widgets/pie-chart) widget.

## Fixes

* Fixed an issue where logging into an App with a username and password assigned the anonymous user identity.
* Fixed transparency rendering issues on the bottom tab bar.
* Fixed drag-and-drop interactions for address items when moving them to and from other canvas components.
* Resolved a connection issue in [Production Apps](/production-apps/overview) when communicating with the built-in [timeseries database](/app-builder/build-backend/functions/storage/timeseries-database).
* Resolved unexpected behavior in the [form](/app-builder/build-frontend/widgets/input-widgets/form) widget when reconfiguring data fields.
* Fixed the auto-fill behavior of the [form](/app-builder/build-frontend/widgets/input-widgets/form) widget to gracefully handle input payloads containing more data than configured.
* Improved App deployment stability and resolved minor build pipeline errors.
* Fixed data export functionality in the [data grid](/app-builder/build-frontend/widgets/display-widgets/data-grid) widget.


# v82 — Fully distributed

Aug 28, 2024

<div align="left"><figure><img src="https://lh7-qw.googleusercontent.com/docsz/AD_4nXd0g7bLPr5hP19EXcKk-IGmIJh5cCI9cyT0cILnyViQvDqK0y7N2v0v9QhgkpjFJCGSmf1TtwsutzstMXKksw2w8na-ogZY0ZNXesTswQZh4tmpEvooLKKEIjsglMsD6FavoCLhwTygsI9cI8Bsq7fs9Gc?key=chRXiLUrI54Os_fCIQ1Z3w" alt=""><figcaption></figcaption></figure></div>

## Features

* Released the first fully distributed deployment option. See [Hosting and architecture](/account/hosting-and-architecture).
* Introduced an initial implementation of the [OPC UA server](/app-builder/build-backend/functions/connectors/opc-ua-server) connector.
* Persists [MQTT client](/app-builder/build-backend/functions/connectors/mqtt-client) connections to allow seamless restarts of the authentication server.
* Updated the core UI libraries and implemented license key validation.
* Added a new default fluent theme in the [Theme Editor](/app-builder/build-frontend/theme-editor) that aligns with the Heisenware brand identity.
* Automatically detects and re-establishes services when cloud slave nodes restart.
* Added the [kanban](/app-builder/build-frontend/widgets/display-widgets/kanban) widget.
* Added the [data list](/app-builder/build-frontend/widgets/display-widgets/data-list) widget.
* Added a new [chart](/app-builder/build-frontend/widgets/display-widgets/chart) widget.
* Improved the text box widget in input widgets to support local configuration.
* Enabled reordering functions across different sections in the Backend Builder.
* Introduced the [Heidenhain DNC](/app-builder/build-backend/functions/connectors/heidenhain-dnc) connector.
* Hides void input arguments on the canvas to declutter the workspace.
* Visualizes connections to linked widgets even when their layout sections are closed.

## Fixes

* Fixed an issue where function aliases did not function correctly.
* Resolved a vulnerability that allowed unauthorized logins with incorrect credentials.
* Restored support for Docker Extensions.
* Resolved various CSS and layout rendering issues across the platform.
* Fixed a critical performance bottleneck related to MQTT client authentication.


# v81 — Removing old cruft

Jul 28, 2024

<div align="left"><figure><img src="https://lh7-qw.googleusercontent.com/docsz/AD_4nXfIw0MmFzFIHOaaTs5YQuUe92xJhoqPTsGJPEa6cK3WTRyUsOpmS9rJ1AtcRN-q-YFBC9n3X02U26_yfIa4DhbgdpCXzrzT930lkE44MrMGysoKoDuJ7-wv6VRAHF5yjeI1A-ZwVeLaHrN_wKdvTDRBTFo?key=chRXiLUrI54Os_fCIQ1Z3w" alt=""><figcaption></figcaption></figure></div>

## Features

* Introduced the [App Manager](/app-manager/overview).
* Upgraded user identity services: integrated FusionAuth as the built-in [user management](/app-manager/users-and-access) engine.
* Added support for multiple deployment modes: you can now select between cloud, server, and container options.
* Added configuration options to customize the title and icon displayed in the app bar title.
* App setting modifications no longer require a redeployment to take effect.
* Improved container orchestration: running docker-compose power-cycles now reliably brings up the entire system, including deployed Apps.

## Fixes

* Improved reliability for backend event subscriptions.
* Resolved an issue that prompted users with spurious password entry requests.


# v80 — Chicks on fire

May 15, 2024

<div align="left"><figure><img src="https://lh7-qw.googleusercontent.com/docsz/AD_4nXc0a72bTrXBx67PN1W3ULv1vBLUdTNv_Can7EPyQwms7AYwbk-8TW3RTP9XAMtz_yxaP9Si9-tyTKXo3A2lMCwW0N5sz9lR-MwVYoIjcJsyMKF0_oKSmbYg8pB9U-co7z4pT2XMsG5FpsPG1WMVJC0ko6dY?key=chRXiLUrI54Os_fCIQ1Z3w" alt=""><figcaption></figcaption></figure></div>

## Features

* Added support for Agent and instance wildcards.
* Textareas are now resizable when used as a single input field in input widgets.
* Integrated a Chroma-based vector database with full CRUD operation support for the [RAG AI](/app-builder/build-backend/functions/extensions/rag-ai) extension.
* Added source attribution indicators to the [RAG AI](/app-builder/build-backend/functions/extensions/rag-ai) extension.
* Enabled single-executable, multi-host deployments for Agents and connectors using auto-generated, cached identifiers.
* Added the [relational database](/app-builder/build-backend/functions/storage/relational-database) connector for the Agent to connect to SQL databases locally on your infrastructure.

## Fixes

* Resolved event-handling conflicts that occurred when a single user duplicated active browser tabs.
* Optimized deployment routines to eliminate long wait times when large amounts of App data are already accumulated.
* Reduced expensive, redundant internal rendering cycles for files loaded from the media server in [Media view](/app-builder/build-frontend/widgets/display-widgets/media-view).


# v79 — Nothing is forever

May 10, 2024

<div align="left"><figure><img src="https://lh7-qw.googleusercontent.com/docsz/AD_4nXcec-5C1DrQbaHD3iqIDjLYucRctDvaCA0mWMDtcNUr2uqIUnKx_N1tUMQYGBp-KYlN9jSNqEn6Z-cVyIDVZ8oiQDxy0s8njGpu6KfQapMO2oA_Q3Nsow2_owKHQSjCIR3oQhtflcJ1ltg5A5vC5Ok0UMQ?key=chRXiLUrI54Os_fCIQ1Z3w" alt=""><figcaption></figcaption></figure></div>

## Features

* Introduced the first version of [PDF templates](/app-builder/build-backend/functions/utilities/pdf-templates) and the [PDF Template Editor](/app-builder/build-frontend/pdf-template-editor).
* The entire platform is now available as an [on-premise installation](/tutorials/on-premise-installation), supporting single-container deployments on edge hardware such as IPCs with x86 or arm64 architectures.
* Added tenancy selection for input widgets, allowing inputs to be explicitly shared.
* Added a built-in mailing service to the [email](/app-builder/build-backend/functions/connectors/email) connector.
* Added support for many-to-many associations between tables in [relational databases](/app-builder/build-backend/functions/storage/relational-database).
* Added support for converting non-history tables to history tables, including tracking for all associations in [relational databases](/app-builder/build-backend/functions/storage/relational-database).
* The [Kuando Busylight](/app-builder/build-backend/functions/connectors/kuando-busylight) driver is now available as a local connector running on an Agent.
* Added thousands separators for number input fields inside [form](/app-builder/build-frontend/widgets/input-widgets/form) widgets.

## Fixes

* Fixed the tag box component inside the [form](/app-builder/build-frontend/widgets/input-widgets/form) widget.
* Fixed an issue where default configuration values for the [email](/app-builder/build-backend/functions/connectors/email) connector failed to load properly.
* Fixed image rotation issues and optimized file sizes when combining the [upload](/app-builder/build-frontend/widgets/input-widgets/upload) widget with the [photo](/app-builder/build-frontend/widgets/input-widgets/photo) widget.


# v78 — Keep moving

Jan 24, 2024

<div align="left"><figure><img src="https://lh7-qw.googleusercontent.com/docsz/AD_4nXdW7Yf_ODib7ntz8RSmpC_826IwdjkPBHZw4qXklfVbf3GIZ8Dbk-tzWxOQoCrOuNK3hf_0NuP4dbJcn102CU1woFFnA25U6pVQ_n2_hbaIbDEd5eGb7EV4hRh-jKks6BwOyUE0rTaP6Y37loixKI7ZqS-8?key=chRXiLUrI54Os_fCIQ1Z3w" alt=""><figcaption></figcaption></figure></div>

## Features

* Improved the organization of available remote functionality in the [Function Explorer](/app-builder/build-backend/functions/function-explorer).
* Implemented traffic shaping to optimize data polling.
* Added support for duplicating layout sections inside the canvas.
* Added support for duplicating a [page or subpage](/app-builder/build-frontend/page-explorer).
* The reverse proxy now resolves all CORS issues by intercepting corresponding HTTP headers.
* Added a configurable delay setting to pause function execution, designed for sequential, one-by-one API processing.

## Fixes

* Entirely removed the buggy undo and redo features.
* Deleting a [page](/app-builder/build-frontend/page-explorer) now cleans up all its connected resources.
* Fixed an issue where default-detached properties (such as `colCount` on the [form widget](/app-builder/build-frontend/widgets/input-widgets/form)) failed to apply correctly.


# v77 — More intelligence

Dec 21, 2023

<div align="left"><figure><img src="https://lh7-qw.googleusercontent.com/docsz/AD_4nXdfcNVj5MARnW9Mz-s_4hi8IAhJnbMLq5D6csBh7AxAPNi3OJqi6pDXYfpvUxph23RHPRDspFNjTLAvs9uGfQ7OZlJQZ47dXsRfO2ArOaRV_DiDau_siRKvPsiEuR_0NbTKtIbzmasxIFdrWYbvFKBsLxiO?key=chRXiLUrI54Os_fCIQ1Z3w" alt=""><figcaption></figcaption></figure></div>

## Features

* Introduced an artificial intelligence agent that provides a conversational [chat](/app-builder/build-frontend/widgets/display-widgets/chat) interface and an initial [RAG AI](/app-builder/build-backend/functions/extensions/rag-ai) implementation.
* Expanded connection highlighting in the [App Builder](/app-builder/overview). Highlighting works in all directions across the Backend Builder and Frontend Builder. Inputs can now receive data from multiple and mixed sources.
* Animated logos on [functions](/app-builder/build-backend/functions) now visualize active data updates in real time.
* Added support for commenting on functions.
* Improved the user interface when working with large input objects.
* Automatically creates a [tag](/app-builder/deploy-and-maintain) of your App for each new deployed version.

## Fixes

* Improved snapline behavior: Snaplines now react only to visible widgets and appear during resizing. Widgets now snap to a 10px grid for easier alignment.
* Fixed screen scaling for mobile and tablet devices on [Production Apps](/production-apps/overview) and optimized rendering performance.
* Resolved several issues in the [OGC SensorThings API](/app-builder/build-backend/functions/extensions/ogc-sensorthings-api) extension.
* The App installation prompt now only appears on platforms that support Progressive Web Apps (PWAs).
* Removed the buggy undo and redo features.


# v76 — Well cooked

Dec 4, 2023

<div align="left"><figure><img src="https://lh7-qw.googleusercontent.com/docsz/AD_4nXfVbs4GpROZnpCZINh2kTckcLANZ00Wneeb8TaAfVgVCouTSXsLXrF-X8VJ1tLfk-H-UbLCyobo7vgk7ntzI5EP9VEhZwQoigjo-VOrZRgRG3J_D5cvEGencGcWisNdciXr6OCZ0polVQvU0D7RPZpK28M?key=chRXiLUrI54Os_fCIQ1Z3w" alt=""><figcaption></figcaption></figure></div>

## Features

* All upload widgets – including [Upload](/app-builder/build-frontend/widgets/input-widgets/upload) and [Barcode / QR](/app-builder/build-frontend/widgets/input-widgets/barcode-qr) – now display uploaded data in a popover. This keeps widget sizes constant instead of expanding their height as users upload more data.
* Configure the [form widget](/app-builder/build-frontend/widgets/input-widgets/form) to display groups of input elements as tabs.
* The `validate` command is now available for the [form widget](/app-builder/build-frontend/widgets/input-widgets/form).
* Widgets now support individual `default-detached` properties. Currently, the [form widget](/app-builder/build-frontend/widgets/input-widgets/form) supports two properties: `tabView` and `colCount`.

## Fixes

* Linking an output to an input now always triggers an event, even if the corresponding value remains unchanged. This fixes intermittent rendering issues on UI widgets where linked inputs previously only triggered events when values actually changed.
* Improved document recognition in the document scan widget.
* Improved the RFID tag recognition algorithm in the [Zebra RFID IoT](/app-builder/build-backend/functions/connectors/zebra-rfid-iot) connector.
* Cleared the URL on [Production Apps](/production-apps/overview) to remove the Auth0-injected `code` parameter.
* Resolved rendering slowdowns in [Production Apps](/production-apps/overview) when switching between pages of different heights.
* Fixed initial scrollbar rendering issues that occurred when selecting a large screen size in [Production Apps](/production-apps/overview).
* Removed the experimental Jupyter integration.


# Overview

The App Manager is the administrative center of your Heisenware account. Here you create new Apps, monitor account usage, and manage your members.

<figure><img src="/files/35lscLIqulativp85ToH" alt=""><figcaption></figcaption></figure>

## Key features

The App Manager has four main areas:

* [**Apps**](#apps): The default landing page where you create, configure, and deploy Apps. From here, you can also [manage App access and your users](/app-manager/users-and-access).
* [**Dashboard**](#dashboard): A real-time summary of account-wide performance and user metrics.
* [**Members**](/app-manager/members): The interface for inviting and managing your members.
* [**Integrations (inbound)**](/app-manager/inbound-integrations): Monitor and authorize data from [Agents](/app-builder/build-backend/agents), MQTT, and VRPC clients.

## Apps

Manage Apps, their settings, and users inside the Apps panel.

### Create a new App

{% stepper %}
{% step %}

#### Initialize

Click the plus icon in the top bar to create a new App container.

<figure><img src="/files/WxZA0bgUaMGnH3YZg9Md" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}

#### Configure

Enter a name and description, upload an icon, and define your initial [Users and access](/app-manager/users-and-access) settings.

<figure><img src="/files/r089D40241LL6pAbS99V" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}

#### Start building

Click Start App Builder on the App card to open the development environment in a new tab.

<figure><img src="/files/m6QbSZRYekVEr1PYILOb" alt=""><figcaption></figcaption></figure>
{% endstep %}
{% endstepper %}

{% hint style="info" %}
The total number of Apps you can create depends on your plan. [Contact us](mailto:support@heisenware.com) if you need additional Apps for your plan.
{% endhint %}

### App settings

* **Name**: The visible title on desktops, home screens, and browser tabs. Keep this under 10 characters for the best mobile display.
* **Description**: Optional internal notes. These are not visible to users.
* **Icon**: The logo used for the favicon and home screen icon. Works best as a square image. Leave padding around the logo, since mobile devices often apply a circular cutout.
* **Language (Beta)**: Heisenware can automatically translate your App using AI. Supported reference languages include English, German, French, Turkish, Italian, and Spanish. [Contact us](mailto:support@heisenware.com) for access to this feature.

### App status and control

Each App card shows its current availability:

* <mark style="background-color:green;">**RUNNING**</mark>: The App is live and reachable via its URL.
* <mark style="background-color:orange;">**EXITED**</mark>: The App has been manually stopped.
* **CREATED**: The App container exists but has never been deployed.
* <mark style="background-color:red;">**UNAVAILABLE**</mark>: An error has occurred. Try to redeploy.

### Delete an App

Click the red Delete App button to remove an App.

{% hint style="danger" %}

#### Deleting an App is irreversible

There is no undo. Save a [tag](/app-builder/deploy-and-maintain#tags-snapshots) (`.hwt` file) from the App Builder before deleting if you want to preserve your work.
{% endhint %}

<figure><img src="/files/QAy7Yini5N7Fil8iJf65" alt=""><figcaption></figcaption></figure>

### Distribution

Each App is distributed via a unique URL or QR code, both found directly on the App card in the Apps panel.

<figure><img src="/files/9DXBScA2FJokpAaf5kWz" alt=""><figcaption></figcaption></figure>

### Maintenance

To take an App offline, use the action switch on the card to toggle between Run and Stop.

<figure><img src="/files/7Uh8xMEbmh45G0mzn1aT" alt=""><figcaption></figcaption></figure>

## Dashboard

The Dashboard panel gives you a real-time summary of your account's performance, including usage stats like total App views and unique users across all Apps.


# Users and access

Heisenware gives you granular control over who can access your Apps. Each App can have its own security settings, even when several sit in the same workspace.

{% hint style="info" %}

#### Users vs. members

This article covers the users of your Apps. For managing your members, the people who build and manage your Apps, see [Members](/app-manager/members).
{% endhint %}

## Access modes

In the Apps panel, choose from five access options to match your security requirements.

<figure><img src="/files/kopDgXMJC7ogBMlx3ae5" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
You can change these settings at any time, but each change instantly affects all active sessions. Frequent changes may confuse your users.
{% endhint %}

### Public access

* **Option**: *Anyone can use the app*
* **Details**: The App is open. Anyone with the URL or QR code can access the interface immediately. No login is required.

### Shared security

* **Option**: *Users must provide a master password*
* **Details**: You must define a master password in the settings.
* **Session**: The browser stores the authentication in local storage. Users re-enter the password only on a different device, in an incognito window, or after clearing their browser data.

### Individual registration

* **Option**: *Users have to sign up*
* **Details**: Heisenware manages user accounts automatically. Users can register with an email/password or their Google account.
* **Session**: Like the master password, the browser keeps the login state in local storage. Users stay logged in until they log out or clear their browser cache.

### Dual authentication

* **Option**: *Users have to sign up and provide a master password*
* **Details**: Combines the previous two methods. Users must have a personal account and know the shared master password to gain entry.

### Private whitelist

* **Option**: *Only previously invited users can log in*
* **Details**: This opens an email invite form. Only the specific email addresses you invite can register and access the App.
* **Programmatic invite:** With the [`users` class](/app-builder/build-backend/functions/utilities/users) in the backend, you can also invite users programmatically from another App.

## User management

The Users card in each App gives you a real-time view of who is accessing your software.

{% hint style="info" %}

#### Managing users programmatically

You can also manage users from within an App using the [`users` class](/app-builder/build-backend/functions/utilities/users).
{% endhint %}

### Anonymized sessions

For Apps using [Public access](#public-access) or [Shared security](#shared-security), the table shows anonymized strings, IP addresses, and session data so you can track unique device usage.

<figure><img src="/files/Sqjg07SAtcqfcap5jtg1" alt=""><figcaption></figcaption></figure>

### Registered profiles

For Apps using [Individual registration](#individual-registration) or [Dual authentication](#dual-authentication), the table shows names and usernames (email addresses). Heisenware recognizes a user logging in from different devices with the same email as the same person.

<figure><img src="/files/Kt22no4d3HH2AmqGdvbY" alt=""><figcaption></figcaption></figure>

### Deleting users

To remove a user, registered account or anonymous session alike, click the trash icon in the list. Deleting a user removes their record and ends their current session.

{% hint style="info" %}

#### Leveraging user data in logic

Once a user is authenticated, the Backend Builder exposes their information through the `$USER` system variable. Use it to personalize the UI (e.g. "Welcome, \[Name]"), filter database queries so users see only their own data, or log exactly who performed an action in your backend.

For example, if a table stores each row's owner in an `email` field, a `getTableData` function can filter for the logged-in user's own rows:

```yaml
# name
orders
# options
filter: ['email', '=', $USER]
```

{% endhint %}


# Integrations (inbound)

The Integrations panel gives you a central overview of every inbound data connection from external systems. Whatever sends data to Heisenware, an IoT sensor, a custom Python script, or a Heisenware Agent, shows up here.

<figure><img src="/files/K7fkGuejTTyOxQEFDQfs" alt=""><figcaption><p>Integrations panel</p></figcaption></figure>

## Integration types

Heisenware connects external data three ways:

### Native or Docker Agent

[Agents](/app-builder/build-backend/agents) securely bridge data from private networks (on-premises servers, local databases) to the cloud.

* **Setup**: You create and deploy Native Agents directly in the App Builder. You download and deploy Docker Agents via Docker.
* **Management**: Once deployed, an Agent entry appears in the Integrations panel for monitoring. No manual credentials required.

### MQTT client

The standard choice for general IoT use cases. Use this for sensors or devices that push data to Heisenware's MQTT broker. Inside your Apps, the [MQTT client connector](/app-builder/build-backend/functions/connectors/mqtt-client) handles these messages. For a full walkthrough, see [Connect an external MQTT client](/tutorials/integration-guides/connect-an-external-mqtt-client).

### [VRPC](/advanced/vrpc) client

An advanced method for connecting custom code and proprietary libraries, the most powerful option for specialized software integrations.

## Connecting MQTT and VRPC clients

Agents connect automatically, but MQTT and VRPC clients need authorization one of two ways:

### Method 1: Manual credential creation

Use this method to pre-configure your external client with a fixed username and password.

{% stepper %}
{% step %}

#### Create

Click Create in the Integrations panel.
{% endstep %}

{% step %}

#### Select type

Select if you need an MQTT or VRPC client.
{% endstep %}

{% step %}

#### Edit/copy credentials

Copy the generated credentials or edit them to your needs.
{% endstep %}

{% step %}

#### Connect

Paste these credentials into your external client's configuration.
{% endstep %}
{% endstepper %}

### Method 2: Smart onboarding

The preferred, passwordless method. The external client sends a request, and you approve it in the App Builder. For a detailed guide, see the [smart onboarding section](/app-builder/build-backend/functions/function-explorer#smart-onboarding).

## Integrate custom code via VRPC

To integrate your code, write a [Code Adapter](/account/hosting-and-architecture#custom-code-adapters) around your existing functions, then load it as a Custom Extension.

* **Supported languages**: Arduino (ESP32), C++, Node.js, and Python.
* **Use cases**: Integrating legacy systems, running complex algorithms, or using specialized software libraries.

{% hint style="info" %}

#### Technical implementation

For details, examples, and adapter setup, visit our [VRPC developer section](/advanced/vrpc).
{% endhint %}


# Members

Members are the developers and admins who build and manage Apps in a Heisenware account. Open the Members panel to manage your team.

{% hint style="info" %}

#### Members vs. users

Members build the Apps. Users are the people who use your published Apps. To manage permissions for your users, see [Users and access](/app-manager/users-and-access).
{% endhint %}

In the Members panel you can:

* **Invite**: Enter an email address in the top-right box and click Invite.
* **Verify**: If a member didn't receive their invite email, click the resend icon (<i class="fa-arrow-rotate-right">:arrow-rotate-right:</i>).
* **Delete**: Click the trash icon (<i class="fa-trash">:trash:</i>) to remove a member. This immediately revokes their access to the account.

<figure><img src="/files/3nkZI79qbZyBcYM0vU6O" alt="" width="563"><figcaption></figcaption></figure>


# Overview

The App Builder is a core component of the Heisenware platform: a visual development environment where you build, test, and deploy Apps. You open it straight from the App Manager, and it focuses on one App at a time.

## Main interfaces

The App Builder splits into four areas that cover the App lifecycle and development workflow.

* **Top Bar (top)**: Opens the [Theme Editor](/app-builder/build-frontend/theme-editor) and [PDF Template Editor](/app-builder/build-frontend/pdf-template-editor), and gives access to App Builder settings, language, and help. It also shows the current App version and holds the controls to [test and deploy](/app-builder/deploy-and-maintain).
* **Explorers (left)**: Switch between the [Function Explorer](/app-builder/build-backend/functions/function-explorer) for backend logic, the [Page Explorer](/app-builder/build-frontend/page-explorer) for frontend structure, and the [File Explorer](/app-builder/build-backend/file-explorer) for resources needed during app development.
* **Backend Builder (center)**: An infinite drawing area where you create the [business logic](/app-builder/build-backend) of your entire App by wiring up selected functions into automated flows.
* **Frontend Builder (right)**: A page-specific design canvas for composing user interfaces for all screen sizes. This is where you [build user interfaces (UI)](/app-builder/build-frontend) using text, images, and interactive widgets.

<figure><img src="/files/9DnPdA04wwiXugoO3M9u" alt=""><figcaption></figcaption></figure>

## How it works

Heisenware uses a highly integrated development process. Rather than working in isolated stages, you build logic, design interfaces, and configure data connections simultaneously within a single environment.

### Build backend

In the [Backend Builder](/app-builder/build-backend) you create event-driven logic by dragging [functions](/app-builder/build-backend/functions) from the [Function Explorer](/app-builder/build-backend/functions/function-explorer) onto the canvas and wiring them into flows. Functions are the atomic building blocks of an App: standard utility blocks, industrial drivers, and custom Code Adapters written in Node.js, Python, or C++.

This logic runs in a global scope. It persists and runs independently of the active UI page, which makes the backend the central hub for continuous data processing or system monitoring. To reach machines and databases in isolated networks, you configure [Native Agents](/app-builder/build-backend/agents/native-agent) or [Docker Agents](/app-builder/build-backend/agents/docker-agent) that tunnel data from local systems directly into your App's logic.

### Build frontend

The [Frontend Builder](/app-builder/build-frontend) is a canvas on which you design your UI per page and across different screen sizes, similar to popular presentation tools such as Google Slides or PowerPoint. You use the [Page Explorer](/app-builder/build-frontend/page-explorer) to create, nest, and organize your pages, then switch to the page you want to edit.

You compose each page from widgets, functional components like gauges, charts, and input fields that you drag onto the canvas. To keep every page and widget visually consistent, the Theme Editor defines the styles and colors that apply across the whole App.

### Unified data binding

The App Builder's core strength is data binding: connect almost any element to any other and data flows between the App's interface and its logic in both directions.

* **Connect anything to everything**: Link a button to a function trigger, bind an input field to a function's input parameters, or feed a function's output into a widget to visualize data, toggle a button's state, or update a gauge's value.
* **Property and event binding**: A property is anything about a widget that can change, its value, scale, visibility, color, and more. Bind backend logic to any property, or to a widget's events, to drive the UI dynamically.
* **Reactive synchronization**: No manual glue code. Interface and logic stay in sync in real time as data flows through the App.

<figure><img src="/files/5Tpl0IjrSzBi7C4d2SZC" alt=""><figcaption></figcaption></figure>

## App Builder settings

Customize how the App Builder behaves and how you control the canvas. To access these preferences, click the settings icon in the Top Bar.

<figure><img src="/files/wnngGWse3iKEm9DfGZkM" alt="" width="367"><figcaption></figcaption></figure>

### Viewport controls

Defines the navigation logic of the Backend Builder canvas. Choose between two modes:

* **Design-tool-like**: Mimics the behavior of tools like Figma or Miro.
* **Google-maps-tool**: Navigation behaves like an interactive map.

### Grid and snapping

* **Grid size**: Defines the size of the canvas grid.
* **Snap to grid**: When enabled, function blocks align to the grid for a cleaner layout. Setting the grid size to 0 disables snapping entirely.

### Navigation (WASD)

Fine-tune keyboard navigation on the canvas:

* **Invert WASD controls**: Switches the direction of the W, A, S, and D keys. By default, W is up and S is down.
* **Pan speed**: Controls how fast the camera moves across the canvas when using WASD.
* **Zoom speed**: Controls the sensitivity of the Q (zoom out) and E (zoom in) keys.

### Default modifier type

Every time you add a [modifier](/app-builder/build-backend/extension-nodes/modifier), Heisenware defaults to a specific type. Choose which one appears first:

* **JSONata**: Ideal for data transformation and querying.
* **JavaScript**: Use this if you prefer writing standard JS logic for your modifiers.

### Debug backend

Enables advanced backend debugging.

{% hint style="danger" %}
This setting should typically remain off. It is intended for support cases when working directly with the Heisenware technical team.
{% endhint %}


# Build backend

The backend is the working core of your App. It fetches, processes, and stores data, talks to machines and external systems, and drives everything users see in the UI. You build it visually by wiring functions into flows on a global canvas.

{% hint style="info" %}

#### Always-on logic

Backend logic runs in the background, even when no user has the App open. This makes the backend the central hub for continuous data processing and system monitoring.
{% endhint %}

## Core backend components

* [**Functions**](/app-builder/build-backend/functions): The atomic building blocks of your logic. They fetch data, process information, manage databases, and control devices. Find them all in the [Function Explorer](/app-builder/build-backend/functions/function-explorer).
* [**Extension nodes**](/app-builder/build-backend/extension-nodes): Modifiers, filters, recorders, and error handlers that refine data directly inside a flow.
* [**Agents**](/app-builder/build-backend/agents): Standalone gateways that execute logic (like connectors) directly inside a local network, for example on a factory floor, and tunnel the data securely into your backend.
* [**Files**](/app-builder/build-backend/file-explorer): CSVs, PDFs, images, and other resources your logic or UI reads from and writes to. Manage them in the File Explorer.

## Backend Builder

Turn individual functions into automated flows inside the Backend Builder. Drag functions onto the infinite canvas and wire them together. Data moves directly from one function's output to the next function's input, creating reactive, event-driven sequences. Each function on the canvas is a function node. Together with extension nodes, they form the building blocks of every flow.

### Adding functions

* **From the Explorer**: Drag functions from the [Function Explorer](/app-builder/build-backend/functions/function-explorer) in the left panel onto the canvas.
* **Quick access**: Use the toolbar for common utilities like `echo`, `memory`, `trigger`, or `combine`.

<figure><img src="/files/8lmJgyGQ3x2p3hXaQBPV" alt="" width="563"><figcaption></figcaption></figure>

### Sequencing functions

Create flows by drawing wires between functions. Click the output of a function (or a [modifier](/app-builder/build-backend/extension-nodes/modifier) attached to it) and drag the wire to the part of the next function that receives it.

* **Output to trigger**: The completion of the first function executes the second, without handing over data.
* **Output to input**: Hands over specific data to the next function.
* **Reactive inputs**: You can internally connect an input to its trigger. The function then executes automatically whenever that input value updates.

Functions only execute when they receive a trigger or a data update. One output can drive multiple functions, and inputs can receive data from many sources across the canvas or UI.

{% hint style="info" %}

#### Session isolation

Functions and flows execute in isolation for each user session. Each session keeps its own state and execution path, so data processing for one user or machine never interferes with another.
{% endhint %}

### Grouping (sections)

Keep a growing canvas clean by grouping functions. Select multiple functions and click the group icon in the toolbar to create a named container that you can collapse to save space. Groups are a visual aid only and have no impact on how the logic executes.

To bundle functions into a reusable custom function instead, use a [subflow](/app-builder/build-backend/functions/subflows).

<figure><img src="/files/dVJCy9kCeZ7aeLs9zo3c" alt="" width="563"><figcaption></figcaption></figure>

### Annotations

Place free-text notes anywhere on the canvas using the annotation tool, for example to document complex logic paths or leave instructions for other developers.

<figure><img src="/files/IcEDwkkCibbB1QvS87EA" alt="" width="563"><figcaption></figcaption></figure>

### Tidying the canvas

The Backend Builder previews layout changes before applying them: every moved node turns orange. Confirm the new layout with the check icon or revert it with the round arrow icon; both icons appear in the toolbar.

* **Clear collisions** (snowplow): Moves functions, extension nodes, sections, and other canvas elements just enough to remove overlaps between nodes. Start it from the toolbar.
* **Auto-format all**: Rebuilds the entire layout. An algorithm groups connected logic into islands and arranges all elements for readability. Start it from the toolbar.
* **Placing new nodes**: When you drop a new function or extension node onto the canvas, nearby nodes shift automatically to make room. Confirm or revert the shift the same way.

### Navigating the canvas

* **Panning**: Use your trackpad, or hold Shift + mouse wheel for horizontal movement and the mouse wheel alone for vertical movement. You can also pan with WASD on your keyboard.
* **Zooming**: Use trackpad pinch-to-zoom or hold Ctrl + mouse wheel. You can also zoom with Q and E on your keyboard.

{% hint style="info" %}
Customize these controls (like mouse wheel behavior) in the [App Builder settings](/app-builder/overview#app-builder-settings).
{% endhint %}

### Search and replace

Change the configuration of many functions at once. Select at least two functions to activate the search and replace tool in the toolbar, then find a specific string (such as a device's IP address) and replace it with a new value across the whole selection.

{% hint style="warning" %}
Search and replace currently only supports strings without spaces.
{% endhint %}

<figure><img src="/files/fLEYYsGKN73QlUAtY5Bp" alt="" width="563"><figcaption></figcaption></figure>


# Functions

Functions form the core building blocks of logic in your Apps. They visually represent code that retrieves data, processes information, manages databases, and controls devices.

Every function follows the same anatomy, represented by a colored box with a unique icon.

<figure><img src="/files/3W5vcHZFAJJQNAR9ulgh" alt=""><figcaption><p>A function merging two or more objects</p></figcaption></figure>

* [**Inputs**](#inputs-and-data-configuration): Arguments the function requires to operate, such as a number to calculate or a string to send. The platform hides the input box if a function does not require inputs. Some functions let you add extra inputs. Click the pencil icon to modify input data via a form, or use YAML during development.
* [**Trigger**](#triggers-and-execution-logic): The signal that executes the function, such as a button click or a data change. Click the play icon to run the function manually during development.
* [**Output**](#outputs-and-chaining): The result of the operation, which passes to the next step in the flow. Click the x icon to clear the output during development.
* [**Extension nodes**](/app-builder/build-backend/extension-nodes): Optional separate nodes that receive data from a function to filter, record, modify, or handle errors in real-time.

## Function categories

Available functions reside in the Function Explorer on the left side of the canvas. Browse them by category in their respective reference sections:

* [**Connectors**](/app-builder/build-backend/functions/connectors): Integration functions for industrial protocols and external systems, including MQTT, OPC UA, Siemens S7, and SAP Digital Manufacturing.
* [**Storage**](/app-builder/build-backend/functions/storage): Relational database and timeseries database classes that connect to databases. Both include a built-in internal database (PostgreSQL and InfluxDB). This category also contains lightweight data stores, such as the data store and circular buffer.
* [**Utilities**](/app-builder/build-backend/functions/utilities): Classes for data processing, timers, cron jobs, barcode generation, and PDF processing.
* [**Extensions**](/app-builder/build-backend/functions/extensions): Docker-based modules that extend the platform, such as RAG AI or process simulations.
* **Custom**: User-defined building blocks, including [subflows](/app-builder/build-backend/functions/subflows) and functions loaded via Custom Extensions.

## Types of functions

The platform classifies functions into four types based on how they manage state or context.

<table><thead><tr><th width="227.3770751953125">Type</th><th>Description</th></tr></thead><tbody><tr><td><strong>Static functions</strong></td><td>Standalone utilities that process data without context (for example, <code>mergeObjects</code>, <code>mapRange</code>, or <code>echo</code>).</td></tr><tr><td><strong>Member functions</strong></td><td>Actions linked to a specific instance. They use the unique configuration and connection settings stored in that instance (for example, <code>read</code>, <code>write</code>, or <code>publish</code>).</td></tr><tr><td><strong>Constructor functions</strong></td><td>Functions named <code>create</code> that configure and initialize a new instance.</td></tr><tr><td><strong>Destructor functions</strong></td><td>Functions named <code>delete</code> that remove an instance to free system resources.</td></tr></tbody></table>

{% hint style="info" %}

#### Concept example: OPC UA client

* **Class**: The generic blueprint for the OPC UA client.
* **Create a specific instance**: Use the `create` function to set an instance name and authorization details, which creates an instance such as `myMachine`.
* **Member functions**: Use the `connect` function of `myMachine` to establish a connection to a server endpoint URL, then use `read` to retrieve data. All member functions of `myMachine` share this connection.
  {% endhint %}

## Work with functions on the canvas

* **Add**: Drag a function from the Function Explorer onto the canvas.
* **Sequence**: Create a flow by drawing a wire between nodes. See [Sequencing functions](/app-builder/build-backend#sequencing-functions).
* **Configure**: Click a function to open its configuration panel. Use YAML for static data or data binding for dynamic data from other functions or widgets.
* **Documentation**: Click the info icon next to a function name to open its documentation panel.
* **Comment**: Right-click a function and select comment to add context.
* **Delete**: Select the function and press the Delete key, or click the trash icon.

{% hint style="danger" %}

#### Permanent deletion

Deleting a function permanently removes its configuration and all connected wires. This action cannot be undone.
{% endhint %}

### Status indicators

A colored status indicator icon appears next to each function name. Hover over the indicator to view status details:

* **Green**: Ready or normal operation.
* **Blue**: Slow execution (greater than two seconds).
* **Yellow**: The required instance does not exist.
* **Red**: An error or exception occurred.
* **Gray**: The function is offline or unavailable.

## Inputs and data configuration

Inputs determine function behavior. Provide data using three methods:

1. **Static data**: Fixed values typed directly into the function input using YAML, or configured via a form by clicking the pencil icon.
2. **Dynamic logic**: Data passed from the output, modifier, or filter of a preceding function.
3. **UI binding**: Live data mapped from a frontend widget (for example, a text field value).

<figure><img src="/files/dlyQyQoO5Gnf8GdneHSd" alt=""><figcaption><p>Function with input in YAML format</p></figcaption></figure>

### YAML input

The platform uses YAML for configuration because it provides a human-readable format for complex data structures.

<details>

<summary><strong>YAML cheat sheet</strong></summary>

#### Basic values (scalars)

Enter simple data types without quotes.

* **Strings**: `Hello world`. Use quotes if the string resembles a number or boolean (for example, `'123'` or `'true'`).
* **Numbers**: `101` or `3.14159`.
* **Booleans**: `true` or `false`.
* **Null**: `null` represents an empty or non-existent value.

#### Lists (arrays)

A collection of items.

* **Block style**: Start each item on a new line with a hyphen.

  ```yaml
  - Apple
  - Orange
  - Banana
  ```
* **Compact style**: Enclose items in square brackets.

  ```yaml
  [Apple, Orange, Banana]
  ```

#### Objects (key-value maps)

Data grouped under specific keys.

* **Block style**: Place each key-value pair on its own line. Use indentation for nested properties.

  ```yaml
  user:
    name: Alex
    email: alex@example.com
    permissions:
      can_read: true
      can_write: false
  ```
* **Compact style**: Enclose comma-separated key-value pairs in curly braces.

  ```yaml
  { name: Alex, email: alex@example.com }
  ```

#### Multiline strings

Use multiline strings for large text blocks, code scripts, or templates.

* **Literal style (`|`)**: Preserves all line breaks exactly. Use this style for raw code or printer layouts (for example, ZPL).

  ```yaml
  |
    ^XA^FO30,80^BQN,2,3^FDLA,{{assetId}}#{{date}}^FS
    ^FO120,140^A0N,22,22^FD{{assetId}}#{{date}}^FS
    ^RFW,A^FD {{assetId}}^FS
    ^XZ
  ```
* **Folded style (`>`)**: Converts single newlines into spaces, which creates a continuous sentence from multiple lines. Blank lines remain as newlines.

  ```yaml
  description: >
    This is a long description written across
    multiple lines in the editor, but processed
    as a single, continuous sentence.

    A new paragraph starts after a blank line.
  ```

</details>

{% hint style="info" %}
Right-click a function input to switch between the YAML and HTML views, or to mask the value by defining it as a secret.
{% endhint %}

### Callbacks

Most functions that use callbacks have an `on` prefix – such as `onMessage`. These functions listen continuously for external events, like an incoming MQTT message, and deliver that data through a specific nested output inside the function input. Throughout the configuration examples in these docs, this special input argument is named `listener`.

<figure><img src="/files/WwkBInQiFJgEt3zeXYit" alt="" width="563"><figcaption><p>A function with a callback listening for incoming MQTT messages in binary format</p></figcaption></figure>

## Triggers and execution logic

The trigger determines when a function runs.

### Trigger sources

* **Data-driven**: Connect a function trigger to an output, modifier, or filter. The default execution mode is update (`on output update`). Click the mode text to switch to change or true.
* **UI events**: Connect a widget event (such as a button's `on button click`) to the trigger.
* **App lifecycle**: Right-click the trigger and select App start > once on deploy, or select App stop. The trigger then displays `once when app starts` or `once when app stops`.
* **Page load and reload**: Right-click the trigger and select App start > once on (re-)load to execute the function whenever a user loads or reloads (refreshes) the App in the browser.
* **Periodically**: Right-click the trigger and select an interval under App start, from every 0.1s to every 1d.
* **Page load**: Drag a page from the Page Explorer onto the trigger to execute the function when that page loads.
* **Manual development**: Click the play icon inside the trigger to run the function manually during development.

<figure><img src="/files/jhnB52nGgaJtpvfIFuKs" alt="" width="563"><figcaption><p>Use page load to execute a function</p></figcaption></figure>

<figure><img src="/files/pvpwLECQJDIz1kakkKN3" alt="" width="563"><figcaption><p>Use a button click to execute a function</p></figcaption></figure>

### Sequential processing of arrays (looping)

To process an array item by item:

1. Right-click the trigger.
2. Select Process one by one.
3. Choose the input containing the target array. The trigger wire changes to a dotted line, indicating that the function executes once for each item in the list.

<details>

<summary><strong>Example: Merge an element into an array</strong></summary>

Sequential processing lets you merge a single element into each sub-array of a larger array.

The image below shows a `combine` function with its trigger configured to process one by one on its first input (`On arg 1`). The function executes for each sub-array, merging the singular element from the second input into both sub-arrays.

<figure><img src="/files/iZtP8KETVYqT4jTxZE75" alt=""><figcaption></figcaption></figure>

</details>

### Delayed execution

Add a delay between 0.1 and 2.0 seconds to any trigger to manage execution timing, such as waiting for a UI animation to complete before retrieving data.

## Outputs and chaining

The output returns the result of the function execution to pass data and control logic throughout your App.

### Return data types

Depending on the function, the output delivers:

* **Standard data**: JSON objects, strings, numbers, or arrays.
* **Binary content**: Files or images, such as generated PDF documents or camera captures.
* **Success flags**: A boolean value (`true` or `false`) indicating whether an operation, such as a database write, succeeded.

### Backend logic (flows)

Link an output to another function to create a functional flow:

* **Pass data**: Connect an output to an input to use the result of the first function as an argument for the next function.
* **Control flow**: Connect an output to a trigger so the subsequent function executes only after the first function completes successfully.

### UI interaction

Link an output directly to the frontend to drive user interface components:

* **Visualize data**: Connect the output to a display widget, such as a chart or value box.
* **Control properties**: Connect the output to a widget and select the property to control, such as dynamically setting a button to disabled.
* **Navigate screens**: Connect the output to a page switch trigger to change pages automatically based on backend logic.

## Extension nodes

Extension nodes attach to a function output to process data directly within the flow. Modifiers transform data, filters gate execution, recorders store information, and error handlers catch exceptions.

* **Add**: Click the plus icon (`+`) on an output and select an extension node type. You can attach multiple parallel extension nodes to a single output.
* **Chain**: Attach an extension node to the output of another extension node to create a multi-step data pipeline.
* **Delete**: Right-click an extension node and select Delete.

## Data binding (connecting to UI)

Functions communicate bidirectionally with frontend widgets through data binding:

* **Input binding**: Links a widget property, such as `formData`, to a function input.
* **Trigger binding**: Links a user action, such as `on button click`, to a function trigger.
* **Output binding**: Links a function result to a widget property, such as `data`, to update the user interface.

## Advanced addressing

Every function targets its underlying backend code using a specific address structure. To view or edit this path, right-click the function name and select *Use dynamic address*.

<figure><img src="/files/BDkT6RlxjAkTprSGBA5A" alt=""><figcaption><p>Right-click the function name and choose Use Dynamic Address</p></figcaption></figure>

This action reveals the exact path to the code, consisting of up to three boxes:

`<Agent/Service> <Class> [Instance]`

* **Box 1 (Agent/Service)**: The runtime or program executing the function. This can be a generic internal service or a specific Agent running on local infrastructure.
* **Box 2 (class)**: The code class name, such as `Busylight`, `Barcode`, or `OpcuaClient`.
* **Box 3 (instance)**: The specific instance name, such as `server1`. This box only appears for member functions. Static functions do not utilize an instance, so the platform hides this box.

<figure><img src="/files/faiMQDHA0xRXbO4f2wPR" alt=""><figcaption><p>Addresses of a static function and a member function</p></figcaption></figure>

Edit this address directly in the boxes if required. The platform retains your changes if you switch back to the standard view.

{% hint style="info" %}

#### Swap Agents across environments

When moving logic between environments, such as from a test device to a production machine, update the Agent name in box 1 to target the new Agent instead of rewiring the flow.

You can use search and replace to update the Agent name across multiple functions simultaneously. This works for all addresses, even if they do not use the dynamic view.
{% endhint %}


# Function Explorer

The Function Explorer is the panel on the left that holds all functions available to your App. It organizes them into categories and hierarchies (classes and instances) and lets you drag them directly onto the Backend Builder canvas.

<figure><img src="/files/kVriuFkCwmokR3owN27V" alt=""><figcaption></figcaption></figure>

## Categories

* [**Connectors**](/app-builder/build-backend/functions/connectors): Integration functions for industrial protocols and external systems. Connectors in this category require the target system to be reachable over the network or internet.
* [**Storage**](/app-builder/build-backend/functions/storage): The relational database and timeseries database classes to connect to databases, including the built-in internal PostgreSQL and InfluxDB. Also holds lightweight stores like the data store and circular buffer.
* [**Utilities**](/app-builder/build-backend/functions/utilities): Data processing, timers, cron jobs, barcode generation, PDF processing, and more.
* **Custom**: Your building blocks, including [subflows](/app-builder/build-backend/functions/subflows) and functions loaded via Custom Extensions.

In addition to the categories, every installed and started [Agent](/app-builder/build-backend/agents) appears as its own entry, listed by its name and holding the connector classes selected when building it.

## Toolbar

The icons at the top of the panel extend your function library:

* **Create Agent** (<i class="fa-cloud-arrow-down">:cloud-arrow-down:</i>): Build and download a new [Agent](/app-builder/build-backend/agents).
* **Install extension** (<i class="fa-puzzle-piece">:puzzle-piece:</i>): Add official or Custom [Extensions](/app-builder/build-backend/functions/extensions) to your library.
* **Smart onboarding** (<i class="fa-screencast">:screencast:</i>): Pair external clients, such as IoT devices, with your account. See [smart onboarding](/app-builder/build-backend/functions/connectors#smart-onboarding).
* **Collapse** (<i class="fa-chevrons-up">:chevrons-up:</i>): Collapse all open entries.


# Connectors

Connectors are [functions](/app-builder/build-backend/functions) that handle translation between Heisenware and external systems. They let flows communicate natively with third-party systems, industrial protocols, and external databases.

## Connection scenarios

The network location of the target system determines where a connector executes.

### Direct connection

When the platform can reach the target system directly, execute the connector in the application backend. The platform automatically manages the connection and execution. This scenario applies to:

* The Heisenware Cloud reaching systems on the public internet, such as a cloud API, a web service, or a public MQTT broker.
* An [on-premise installation](/tutorials/on-premise-installation) reaching systems within the same network.

### Local connection (via Agent)

If the target system resides in an isolated network segment without inbound access (such as a PLC in a machine network), deploy an Agent. Agents are available as a [Native Agent](/app-builder/build-backend/agents/native-agent) or a [Docker Agent](/app-builder/build-backend/agents/docker-agent).

{% stepper %}
{% step %}

#### Build

Compile a Native Agent directly inside the [App Builder](/app-builder/overview) and select which connectors to include in the package.
{% endstep %}

{% step %}

#### Deploy

Install the binary on a target system within the local network.
{% endstep %}

{% step %}

#### Use

Once the Agent comes online, it appears automatically in the [Function Explorer](/app-builder/build-backend/functions/function-explorer). The Agent displays the connectors selected during the build. These functions execute directly at the edge, next to local devices.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
For a deep dive into the build process and deployment options, see the [Agents](/app-builder/build-backend/agents) article.
{% endhint %}

## Instance creation

Most connectors require an instance configuration before they can interact with a target system. Create an instance using the `create` function. The instance preserves configuration schemas, tracks credentials, and manages the connection lifecycle.

Certain connectors provide purely static utilities (such as [File I/O](/app-builder/build-backend/functions/connectors/file-i-o) or the [Operating System (OS)](/app-builder/build-backend/functions/connectors/operating-system-os)) and execute calls immediately without an instance configuration.

## Available connectors

The following table lists the available connectors and their required configuration types. Each link leads to a detailed configuration guide.

| Connector                                                                                              | Description                                                                         | Type                                |
| ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- | ----------------------------------- |
| [Allen-Bradley](/app-builder/build-backend/functions/connectors/allen-bradley)                         | Connects directly to Allen-Bradley PLCs for machine data acquisition and control.   | Instance creation required          |
| [Email](/app-builder/build-backend/functions/connectors/email)                                         | Sends emails via SMTP.                                                              | Instance creation required          |
| [File I/O](/app-builder/build-backend/functions/connectors/file-i-o)                                   | Reads from and writes to files on a connected file system.                          | Static functions only               |
| [GraphQL](/app-builder/build-backend/functions/connectors/graphql)                                     | Interacts with any GraphQL API for flexible data queries.                           | Static functions only               |
| [GPIO counter](/app-builder/build-backend/functions/connectors/gpio-counter)                           | Counts digital pulses on Raspberry Pi GPIO pins, with automatic run/stop detection. | Instance creation required          |
| [Heidenhain DNC](/app-builder/build-backend/functions/connectors/heidenhain-dnc)                       | Connects to Heidenhain DNC systems and requires a local connection scenario.        | Instance creation required          |
| [Heidenhain OPC UA](/app-builder/build-backend/functions/connectors/heidenhain-opc-ua)                 | Connects to Heidenhain controllers using the OPC UA protocol.                       | Instance creation required          |
| [HTTP / REST](/app-builder/build-backend/functions/connectors/http-rest)                               | Makes requests to standard web APIs and HTTP endpoints.                             | Mixed (Static and instance options) |
| [Hydra MIP](/app-builder/build-backend/functions/connectors/hydra-mip)                                 | Integrates natively with the Manufacturing Integration Platform (MIP).              | Instance creation required          |
| [Kuando Busylight](/app-builder/build-backend/functions/connectors/kuando-busylight)                   | Controls Kuando Busylight status indicators.                                        | Instance creation required          |
| [Label printer](/app-builder/build-backend/functions/connectors/label-printer)                         | Sends print commands to ZPL-compatible label printers.                              | Instance creation required          |
| [Modbus](/app-builder/build-backend/functions/connectors/modbus)                                       | Communicates with industrial devices using the Modbus protocol.                     | Instance creation required          |
| [MQTT Client](/app-builder/build-backend/functions/connectors/mqtt-client)                             | Connects to an MQTT broker to publish and subscribe to topics.                      | Instance creation required          |
| [OPC UA Client](/app-builder/build-backend/functions/connectors/opc-ua-client)                         | Connects to an OPC UA server for industrial automation data exchange.               | Instance creation required          |
| [OPC UA Server](/app-builder/build-backend/functions/connectors/opc-ua-server)                         | Deploys an OPC UA server to expose data from the application.                       | Instance creation required          |
| [Operating system (OS)](/app-builder/build-backend/functions/connectors/operating-system-os)           | Accesses statistics and information from the host operating system.                 | Static functions only               |
| [Relational database](/app-builder/build-backend/functions/storage/relational-database)                | Connects to external SQL databases.                                                 | Instance creation required          |
| [RS-232/485](/app-builder/build-backend/functions/connectors/rs-232-485)                               | Communicates with devices over a serial port.                                       | Instance creation required          |
| [SAP Digital Manufacturing](/app-builder/build-backend/functions/connectors/sap-digital-manufacturing) | Integrates natively with SAP Digital Manufacturing.                                 | Instance creation required          |
| [Siemens S7](/app-builder/build-backend/functions/connectors/siemens-s7)                               | Connects directly to Siemens S7 PLCs for data acquisition and control.              | Instance creation required          |
| [Timeseries database](/app-builder/build-backend/functions/storage/timeseries-database)                | Connects to external InfluxDB databases.                                            | Instance creation required          |
| [Zebra RFID IoT](/app-builder/build-backend/functions/connectors/zebra-rfid-iot)                       | Interacts with Zebra RFID readers and devices.                                      | Instance creation required          |


# Allen-Bradley

The Allen-Bradley connector communicates with Allen-Bradley programmable logic controllers (PLCs) using the EtherNet/IP protocol. After establishing a connection, the connector automatically discovers all tags at both the controller and program scope. You can then read and write tags individually or in groups, or subscribe to them for real-time updates.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can interact with a PLC.

## Tags and user-defined types

A tag is a PLC variable that represents a named piece of memory with a specific data type, such as `DINT` for a 32-bit integer, `REAL` for a floating-point number, or `BOOL` for a boolean. A user-defined type (UDT) is a structured tag that groups related values into a single unit, similar to an object. For example, a `Recipe` UDT can contain the members `Name` and `TempSetPoint`, which you address as `Recipe.Name` and `Recipe.TempSetPoint`. Reading a UDT returns an object with key-value pairs corresponding to its members.

The connector discovers all tags and their types when you call `connect`, letting you address every tag by its name.

## Connection management

### `create`

Creates a controller instance that represents the connection to a specific PLC. All other functions require this instance.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>ipAddress</code></td><td></td><td>The IP address of the target PLC on the network.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>slot</code></td><td>The slot number of the CPU in the PLC chassis. Default 0.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# ipAddress
192.168.1.10
# options
slot: 2
```

#### Output

Returns the name of the created instance.

### `connect`

Connects to the PLC and discovers all controller-scoped and program-scoped tags to make them available for reading, writing, and subscribing. See [Connection recovery](#connection-recovery) for the behavior after an unexpected session loss.

#### Parameters

None.

#### Output

Returns `true` on a successful connection. Throws an error if the connection or tag discovery fails.

### `isConnected`

Checks the current connection status.

#### Parameters

None.

#### Output

Returns `true` if connected, or `false` if disconnected.

### `disconnect`

Disconnects from the PLC and clears all subscriptions and cached tag information.

#### Parameters

None.

#### Output

Returns `true` on a successful disconnection, including when no active connection exists. Throws an error if the disconnection fails.

### `delete`

Removes the instance and its connection.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To interact with the PLC again, you must trigger `create` and `connect` anew.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Reading and writing

### `readTag`

Reads the current value of a single tag. This function requires an active connection, and the tag must exist in the discovered tag list.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>tagName</code></td><td>The exact name of the tag to read, such as <code>MotorSpeed</code> or <code>Program:MainProgram.MyData.Status</code>.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# tagName
MyTemperature
```

#### Output

Returns the raw value of the tag matching its PLC data type (such as 72.5 for a `REAL` tag). Throws an error if the tag does not exist or the read fails.

### `readTagGroup`

Reads multiple tags in a single, optimized network request. This is more efficient than calling `readTag` repeatedly. The connector skips tags that do not exist in the discovered tag list and logs a warning.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>tagNames</code></td><td>An array of tag names to read.</td><td>array</td></tr></tbody></table>

#### Example

```yaml
# tagNames
[MotorSpeed, Machine_Status, MyTemperature]
```

#### Output

Returns an object where each key is a tag name and each value is its current value. Returns an empty object if none of the requested tags exist:

```json
{
  "MotorSpeed": 1750,
  "Machine_Status": 3,
  "MyTemperature": 72.5
}
```

### `writeTag`

Writes a new value to a tag. The function handles both simple tags (numbers, booleans, strings) and UDTs. For a UDT, provide an object where keys map to the member names. Each member must exist as a discovered tag. A type mismatch throws an error.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>tagName</code></td><td>The name of the tag to target.</td><td>string</td></tr><tr><td><code>value</code></td><td>The value to write. Provide a primitive for simple tags or an object for UDTs.</td><td>any</td></tr></tbody></table>

#### Examples

Example 1: Simple tag

```yaml
# tagName
MotorSpeedSP
# value
150
```

Example 2: UDT

```yaml
# tagName
Recipe
# value
Name: "Batch 2A"
TempSetPoint: 95.5
```

#### Output

Returns `true` on a successful write. Throws an error if the tag is unknown, a type mismatch occurs, or the write fails.

### `writeTagGroup`

Writes values to multiple tags in a single, optimized network request. The connector skips tags that do not exist in the discovered tag list and logs a warning.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>tags</code></td><td>An object where each key is a tag name and each value is the value to write.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# tags
MotorSpeedSP: 1800
Valve_1_Open: true
RecipeName: "Batch 3C"
```

#### Output

Returns `true` when all writes complete. Throws an error if the operation fails.

### `getDiscoveredTags`

Returns a list of all tags discovered during the `connect` phase. Use this for debugging or dynamically exploring a PLC.

#### Parameters

None.

#### Output

Returns an array of tag objects containing detailed schema information for each discovered tag:

```json
[
  {
    "id": 1234,
    "name": "MotorSpeed",
    "type": { "code": 195, "sint": null, "string": "DINT" },
    "structure": false
  },
  {
    "id": 5678,
    "name": "Recipe",
    "type": { "code": 160, "sint": 4321, "string": "MyRecipeUDT" },
    "structure": true
  }
]
```

## Subscriptions

### `subscribe`

Subscribes to one or more tags for real-time updates. When a tag value changes on the PLC, the PLC automatically pushes the new value to the platform. Register a listener using `onData` to handle incoming updates. The connector skips tags that are already subscribed or missing from the discovery list and logs a warning.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>tagNames</code></td><td>A single tag name or an array of tag names to subscribe to.</td><td>string or array</td></tr><tr><td><code>rate</code></td><td>How often the PLC sends updates, measured in milliseconds. Default 500.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# tagNames
[Machine_Status, Production_Count, Pressure_Sensor_1]
# rate
250
```

#### Output

Returns nothing. Data arrives through the listener registered with `onData`. Throws an error if the PLC is not connected.

### `onData`

Registers a callback that fires whenever new data arrives from a subscribed tag. You must subscribe to at least one tag for this listener to receive data.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>listener</code></td><td>Callback that fires on new data. Delivers an object containing <code>tagName</code> and <code>value</code>.</td><td>callback</td></tr></tbody></table>

#### Example

```yaml
# listener
<callback>
```

#### Output

Returns the string `subscribed` to confirm listener registration.

### `onError`

Registers a callback that fires when a subscription error occurs, such as a lost PLC connection.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>listener</code></td><td>Callback that handles the subscription error. Delivers the error object.</td><td>callback</td></tr></tbody></table>

#### Example

```yaml
# listener
<callback>
```

#### Output

Returns the string `subscribed` to confirm listener registration.

## Tips and tricks

### Choosing between polling, subscribing, and group operations

Use `readTag` and `writeTag` for on-demand, request-response interactions. Use `subscribe` alongside `onData` for real-time monitoring and dashboards to let the PLC push changes automatically. When handling multiple tags simultaneously, use `readTagGroup` and `writeTagGroup` to bundle requests into a single network packet and reduce network traffic.

### Connection recovery

If the PLC session closes unexpectedly, the connector clears all discovered tags and active subscriptions while logging a warning. Call `connect` again to re-establish the connection and rediscover the tags, then recreate your subscriptions.


# Email

The email connector sends emails via SMTP by configuring a mail transport once and transmitting messages containing plain text or HTML content alongside any number of attachments.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can interact with an SMTP server, though Heisenware includes a pre-initialized instance out of the box.

{% hint style="info" %}

#### Ready-to-use instance

Heisenware ships with a pre-initialized email instance called `internal-email`. It is always available, letting you call `send` directly.

<img src="/files/QnrP2IQKRmf5Py2iPfW9" alt="" data-size="original">

To send through another mailing system (such as Gmail, Office 365, or a private SMTP server), create a new instance with your server's connection and authentication details.
{% endhint %}

### `create`

Creates a new email client instance by configuring the connection to an SMTP server.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>host</code></td><td>The hostname or IP address of your SMTP server (such as <code>smtp.gmail.com</code>).</td><td>string</td></tr><tr><td></td><td><code>port</code></td><td>The port to connect to. Common values include 465 for SMTPS (use with <code>secure: true</code>), 587 for STARTTLS (use with <code>secure: false</code>), or 25 for unencrypted SMTP. Default 587, or 465 if <code>secure</code> is true.</td><td>integer</td></tr><tr><td></td><td><code>secure</code></td><td>If true, the connection uses direct SSL/TLS. If false, the connection upgrades to TLS via STARTTLS if the server supports it. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>ignoreTLS</code></td><td>If true (and <code>secure</code> is false), the connector does not use TLS even if the server supports STARTTLS. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>requireTLS</code></td><td>If true (and <code>secure</code> is false), the connection must upgrade to STARTTLS, otherwise the connector does not send the message. Default false.</td><td>boolean</td></tr><tr><td><code>auth</code></td><td><code>user</code></td><td>The username, typically your full email address.</td><td>string</td></tr><tr><td></td><td><code>pass</code></td><td>The password for the email account.</td><td>string</td></tr><tr><td></td><td><code>type</code></td><td>The authentication type: <code>login</code> or <code>oauth2</code>. Default <code>login</code>.</td><td>string</td></tr><tr><td><code>defaults</code></td><td></td><td>An object merged into every email sent with this instance, such as to set a shared <code>from</code> address.</td><td>object</td></tr></tbody></table>

For OAuth2 (`type: oauth2`), provide the standard nodemailer OAuth2 keys in `auth` (such as `clientId`, `clientSecret`, `refreshToken`, and `accessToken`).

{% hint style="info" %}
Right-click the `auth` input and mark it as a secret to mask the password.
{% endhint %}

#### Examples

Example 1: Connecting with STARTTLS (such as Office 365)

```yaml
# options
host: smtp.office365.com
port: 587
secure: false
# auth
user: my-user@my-company.com
pass: my-secret-password
# defaults
from: '"My Application" <my-user@my-company.com>'
```

Example 2: Connecting with direct SSL/TLS

```yaml
# options
host: mail.my-legacy-server.com
port: 465
secure: true
# auth
user: my-user@my-legacy-server.com
pass: another-password
```

#### Output

Returns the name of the created instance.

### `send`

Composes and sends an email. The function automatically detects whether `content` is HTML or plain text.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>address</code></td><td><code>from</code></td><td>The sender's address, plain (<code>sender@server.com</code>) or formatted (<code>'"Sender Name" &#x3C;sender@server.com>'</code>). Omit this if the instance defines a default <code>from</code>.</td><td>string</td></tr><tr><td></td><td><code>to</code></td><td>The primary recipient or recipients, provided as a single address, a comma-separated string, or an array of strings.</td><td>string or array</td></tr><tr><td></td><td><code>cc</code></td><td>Carbon copy recipients, using the same formats as <code>to</code>.</td><td>string or array</td></tr><tr><td></td><td><code>bcc</code></td><td>Blind carbon copy recipients, using the same formats as <code>to</code>.</td><td>string or array</td></tr><tr><td><code>subject</code></td><td></td><td>The subject line of the email.</td><td>string</td></tr><tr><td><code>content</code></td><td></td><td>The body of the email, provided as plain text or HTML.</td><td>string</td></tr><tr><td><code>attachments</code></td><td><code>filename</code></td><td>The filename shown in the email. Unicode characters are allowed.</td><td>string</td></tr><tr><td></td><td><code>content</code></td><td>The attachment content as a string, Buffer, or stream. For base64 content, add <code>encoding: base64</code>.</td><td>any</td></tr><tr><td></td><td><code>encoding</code></td><td>The encoding of the <code>content</code> value, such as <code>base64</code>.</td><td>string</td></tr><tr><td></td><td><code>path</code></td><td>A file path to the attachment. This streams the file from disk, which is more memory-efficient for large files than <code>content</code>.</td><td>string</td></tr><tr><td></td><td><code>href</code></td><td>A URL to the file. The connector downloads the content from this URL.</td><td>string</td></tr><tr><td></td><td><code>httpHeaders</code></td><td>Optional HTTP headers to pass with the <code>href</code> request, such as an authorization header.</td><td>object</td></tr><tr><td></td><td><code>cid</code></td><td>A unique content ID to embed the attachment as an inline image in the HTML body (for example, <code>&#x3C;img src="cid:my-image-cid"></code>).</td><td>string</td></tr></tbody></table>

The `attachments` property accepts an array of objects containing the keys listed above. Provide either `content`, `path`, or `href` per attachment.

#### Examples

Example 1: Plain text email

```yaml
# address
to: 'recipient@example.com'
from: '"Support Team" <support@my-company.com>'
# subject
Your recent support ticket
# content
Hello,

This is a confirmation that we have received your support ticket. We will get back to you shortly.

Regards,
The Support Team
```

Example 2: HTML email

```yaml
# address
to: 'customer@example.com'
from: '"Sales" <sales@my-company.com>'
# subject
Your weekly newsletter
# content
'<h1>Our Top Story This Week</h1><p>Check out our latest product, now available for pre-order!</p><a href="https://my-company.com/products/new">Pre-order Now</a>'
```

Example 3: Attachment from a file path

```yaml
# address
to: 'manager@example.com'
from: 'reports@my-company.com'
# subject
Q3 financial report
# content
Please find the Q3 financial report attached.
# attachments
[
  {
    filename: 'Q3-Report.pdf',
    path: '/path/to/local/reports/q3_financials.pdf'
  }
]
```

Example 4: Attachment from a base64 string

```yaml
# address
to: 'client@example.com'
from: 'invoices@my-company.com'
# subject
Your invoice #12345
# content
Your invoice is attached.
# attachments
[
  {
    filename: 'invoice.pdf',
    content: 'JVBERi0xLjQKJ...', # the base64 string
    encoding: 'base64'
  }
]
```

Example 5: HTML email with an inline image

```yaml
# address
to: 'team@example.com'
from: 'marketing@my-company.com'
# subject
Check out our new logo!
# content
'<p>We are excited to unveil our new company logo:</p><img src="cid:logo-image@my-company.com">'
# attachments
[
  {
    filename: 'logo.png',
    path: '/path/to/assets/new_logo.png',
    cid: 'logo-image@my-company.com' # this cid must match the src in the HTML
  }
]
```

#### Output

Returns `true` on a successful send. If the send fails, the function logs the error and returns nothing without throwing an error. The same applies when the instance was created with a failing configuration: the connector then skips sending and logs a warning.

### `delete`

Removes the instance and its configured mail transport.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To send through that server again, you must trigger `create` anew.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## App Builder example

In the example below, a [form](/app-builder/build-frontend/widgets/input-widgets/form) fills the subject and content, an [upload](/app-builder/build-frontend/widgets/input-widgets/upload) widget provides the attachments, and the recipient address is predefined. A button triggers the `send` function.

<figure><img src="/files/PsmUTsiJ9qVkBirKLe3Y" alt=""><figcaption></figcaption></figure>

This is how the email looks:

<figure><img src="/files/yd8MRzDu7i3Ufhd5XR8u" alt=""><figcaption></figcaption></figure>

## Video demo

{% embed url="<https://www.youtube.com/watch?v=G8L-faWSah4>" %}


# File I/O

The file I/O functions read data from multiple file formats (CSV, Excel, PDF, XML, Word, and more), write data to files, and manage files and folders on a file system. All functions in this class are static and execute without an instance configuration.

## Where functions execute

The file system these functions access depends on their execution environment:

1. Platform: When executed directly on the platform, functions access the file system of the platform installation itself, the same content visible in the [File Explorer](/app-builder/build-backend/file-explorer). The root path is `/shared`, meaning a file in the uploads folder uses the path `/shared/uploads/test.csv`.
2. Local OS: To work with files on your premises, compile, download, and install an [Agent](/app-builder/build-backend/agents) containing this class. Functions executed via the Agent access the file system where the Agent runs, using standard local paths like `C:\Users\YourUserName\Documents\test.csv`.

{% hint style="warning" %}

#### Pitfall on Windows

When referencing Windows paths, wrap the YAML input in quotes. Without quotes, `C:\Users` parses as an object containing a `C` key and a `\Users` value. Define paths as `'C:\Users'`.
{% endhint %}

## Reading files

### `read`

Reads a file and automatically parses its content based on the file extension. This function serves as a convenience wrapper that calls the matching specific function (such as `readCsv` or `readXlsx`). Supported extensions include `csv`, `xlsx`, `docx`, `pptx`, `html`, `htm`, `md`, `txt`, `xsl`, `pdf`, and `xml`.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filename</code></td><td>The full path to the file.</td><td>string</td></tr><tr><td><code>options</code></td><td>Options specific to the detected file type. See the respective read function.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# filename
/path/to/my-data.xlsx
```

#### Output

Returns the parsed content of the file (for example, executing this on an `.xlsx` path internally calls `readXlsx` and returns the parsed JSON content). Throws an error for unsupported file types.

### `exists`

Checks whether a file exists at the specified path.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filename</code></td><td>The path of the file to check.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true` if the file exists, or `false` if it does not.

## Working with buffers

### `readFileToBuffer`

Reads any file and returns its entire content as a base64 encoded string.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filePath</code></td><td>The path of the file to read.</td><td>string</td></tr></tbody></table>

#### Output

Returns the file content as a base64 encoded string.

### `writeBufferToFile`

Writes a base64 encoded string to a new file.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filePath</code></td><td>The full path where the file is saved, including the filename and extension.</td><td>string</td></tr><tr><td><code>buffer</code></td><td>The content of the file as a base64 encoded string.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true` on a successful write.

### `writeBuffersToDirectory`

Writes one or more buffer-file objects to a directory. The function creates the directory (including parent folders) if it does not exist.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>dirname</code></td><td>The path to the directory where the files are written.</td><td>string</td></tr><tr><td><code>bufferData</code></td><td>A single object or an array of objects, each containing at least the <code>name</code> and <code>base64</code> properties. See the <a href="/pages/1EApEe0ychZCopvG2pjE#file-object-structure">file object structure</a>.</td><td>object or array</td></tr></tbody></table>

#### Output

Returns `true` when all files are successfully written. Throws an error listing every file that failed.

<figure><img src="/files/74W9ebOK8mHnZyQwUlPe" alt=""><figcaption><p>This function integrates directly with the <a href="/pages/1EApEe0ychZCopvG2pjE">photo</a> or <a href="/pages/FMnSh3Z4kSeixGTgHs7u">upload</a> widget when configured to use <code>Buffer</code> as the storage type.</p></figcaption></figure>

{% hint style="info" %}

#### Local file sharing

Using these functions from an Agent establishes a file share between your App and your local OS. For example, you can store pictures taken with the photo widget directly on your own file server.
{% endhint %}

## Managing files and folders

### `moveFile`

Moves or renames a file.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>oldPath</code></td><td>The original path of the file.</td><td>string</td></tr><tr><td><code>newPath</code></td><td>The new path for the file.</td><td>string</td></tr></tbody></table>

#### Output

Returns nothing on success. Throws an error on failure.

### `copyFile`

Copies a file from a source path to a destination path.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>src</code></td><td>The path of the file to copy.</td><td>string</td></tr><tr><td><code>dest</code></td><td>The path where the copy is created.</td><td>string</td></tr></tbody></table>

#### Output

Returns nothing on success. Throws an error on failure.

### `deleteFile`

Deletes a file.

{% hint style="danger" %}

#### Irreversible action

This permanently deletes the file from the file system. You cannot undo this action.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filename</code></td><td>The path of the file to delete.</td><td>string</td></tr></tbody></table>

#### Output

Returns nothing on success. Throws an error if the file does not exist.

### `createFolder`

Creates a new folder at the specified path, including any missing parent folders.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>path</code></td><td>The path where the new folder is created.</td><td>string</td></tr></tbody></table>

#### Output

Returns nothing on success. Throws an error on failure.

### `deleteFolder`

Deletes a folder and all of its contents recursively. The function does not throw an error if the folder is missing.

{% hint style="danger" %}

#### Irreversible action

This permanently deletes the folder and all containing files and subfolders. You cannot undo this action.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>dir</code></td><td>The path of the folder to delete.</td><td>string</td></tr></tbody></table>

#### Output

Returns nothing.

### `browse`

Recursively scans a folder and returns a structure representing its files and subfolders.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filename</code></td><td>The path of the folder to browse.</td><td>string</td></tr></tbody></table>

#### Output

Returns a nested JSON object detailing the folder's contents, containing the properties `name`, `path`, `size`, `modDate`, `isDir`, and a `children` array for directories:

```json
{
  "id": "12345",
  "path": "/path/to/project",
  "name": "project",
  "modDate": "2025-08-22T12:02:00.000Z",
  "size": 4096,
  "isDir": true,
  "childrenCount": 2,
  "children": [
    {
      "id": "12346",
      "path": "/path/to/project/report.docx",
      "name": "report.docx",
      "modDate": "2025-08-21T10:30:00.000Z",
      "size": 15360,
      "isDir": false,
      "isFile": true,
      "isSymlink": false
    },
    {
      "id": "12347",
      "path": "/path/to/project/images",
      "name": "images",
      "modDate": "2025-08-22T11:00:00.000Z",
      "size": 4096,
      "isDir": true,
      "childrenCount": 1,
      "children": []
    }
  ]
}
```

## CSV files

### `readCsv`

Reads CSV data and converts it into an array of JSON objects. The function automatically detects whether the input is a file path, a raw CSV string, or a base64 encoded string.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>fileInfo</code></td><td></td><td>The path to the <code>.csv</code> file, a raw CSV string, or a base64 encoded string of the file content.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>delimiter</code></td><td>The column delimiter. Provide a string (such as <code>;</code>), <code>auto</code> for automatic detection, or an array of candidates (such as <code>[',', ';', '|']</code>). Default <code>,</code>.</td><td>string or array</td></tr><tr><td></td><td><code>checkType</code></td><td>If true, automatically converts numbers and booleans from strings to their native types. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>noheader</code></td><td>Indicates that the CSV data has no header row. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>headers</code></td><td>An array of strings used as column headers, such as when the CSV has no header row.</td><td>array</td></tr><tr><td></td><td><code>output</code></td><td>The output format: <code>json</code>, <code>csv</code> (array of arrays), or <code>line</code> (each line as a string). Default <code>json</code>.</td><td>string</td></tr><tr><td></td><td><code>trim</code></td><td>Trims whitespace from headers and values. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>ignoreEmpty</code></td><td>If true, ignores empty lines. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>quote</code></td><td>The character used for quoting columns. Default <code>"</code>.</td><td>string</td></tr><tr><td></td><td><code>includeColumns</code></td><td>A regular expression specifying which columns to include.</td><td>string</td></tr><tr><td></td><td><code>ignoreColumns</code></td><td>A regular expression specifying which columns to ignore.</td><td>string</td></tr></tbody></table>

All other [csvtojson](https://www.npmjs.com/package/csvtojson) options pass through directly.

#### Examples

Example 1: Reading a semicolon-delimited CSV with type conversion

```yaml
# fileInfo
/path/to/data.csv
# options
delimiter: ;
checkType: true
```

Example 2: Reading a CSV string with no header row

```yaml
# fileInfo
'1,ProductA,19.99\n2,ProductB,25.50'
# options
noheader: true
headers: ['id', 'name', 'price']
checkType: true
```

#### Output

Returns an array of JSON objects (or the format specified by `output`). Throws an error if the input is neither a valid path, base64 string, nor a valid CSV string.

### `writeCsv`

Converts an array of JSON objects into a CSV string and writes it to a file.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>json</code></td><td></td><td>An array of JSON objects.</td><td>array</td></tr><tr><td><code>filename</code></td><td></td><td>The path where the <code>.csv</code> file is saved.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>keys</code></td><td>An array of strings specifying which properties to include as columns, in order.</td><td>array</td></tr><tr><td></td><td><code>delimiter</code></td><td>The field separator. Default <code>,</code>.</td><td>string</td></tr><tr><td></td><td><code>prependHeader</code></td><td>If false, the connector omits the header row. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>eol</code></td><td>The end-of-line character. Default <code>\n</code>.</td><td>string</td></tr><tr><td></td><td><code>sortHeader</code></td><td>If true, sorts the headers alphabetically. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>emptyFieldValue</code></td><td>The value used for empty, null, or undefined fields. Default <code>''</code>.</td><td>string</td></tr><tr><td></td><td><code>excelBOM</code></td><td>If true, adds a BOM character for correct UTF-8 display in Excel.</td><td>boolean</td></tr></tbody></table>

#### Example

```yaml
# json
[
  { "id": 1, "name": "Product A", "price": 19.99, "stock": 100 },
  { "id": 2, "name": "Product B", "price": 25.50, "stock": 250 }
]
# filename
/path/to/output.csv
# options
keys: ['id', 'name', 'price']
prependHeader: false
```

#### Output

Returns `true` on a successful write.

## Excel files

### `readXlsx`

Reads an Excel file and converts its content into JSON. If the file contains only one sheet (or only one is queried), the result is an array of row objects. For files with multiple sheets, the result is an object containing one key per sheet name.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>fileInput</code></td><td></td><td>The path to the <code>.xlsx</code> file or a base64 encoded string of the file content.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>headerRows</code></td><td>The number of rows from the top treated as a header and excluded from the data.</td><td>integer</td></tr><tr><td></td><td><code>sheets</code></td><td>An array of sheet names to include. Default includes all existing sheets.</td><td>array</td></tr><tr><td></td><td><code>columnToKey</code></td><td>An object whose keys identify xlsx columns and whose values define the corresponding property name in the result.</td><td>object</td></tr><tr><td></td><td><code>range</code></td><td>A cell range to read (such as <code>'A2:C10'</code>).</td><td>string</td></tr></tbody></table>

{% hint style="info" %}

#### Configuration tips

* Use `columnToKey: { '*': '{{columnHeader}}' }` to automatically extract names from the header row.
* Use `columnToKey: { A: '{{A1}}', B: '{{B1}}' }` to use names defined anywhere in the sheet.
* Configure options per sheet by passing objects inside the `sheets` array:

```yaml
sheets:
  - name: sheet1
    range: 'A2:B2'
  - name: sheet2
    range: 'A3:B4'
```

{% endhint %}

#### Examples

Example 1: Reading a specific range with named columns

```yaml
# fileInput
/path/to/report.xlsx
# options
range: 'B2:D10'
columnToKey: {
  B: product,
  C: quantity,
  D: price
}
```

Output:

```json
[
  { "product": "Widget", "quantity": 10, "price": 19.99 }
]
```

Example 2: Reading a table with a single header row and mapped columns

```yaml
# fileInput
/path/to/assets.xlsx
# options
headerRows: 1
columnToKey: {
  B: barcode,
  C: name,
  D: acquired,
  H: keeper,
  K: inventoryNo,
  M: serialNo,
  N: costCtr
}
```

Output:

```json
[
  { "barcode": 187552, "name": "HP Laptop", "acquired": "2025-06-01T00:00:00.000Z" }
]
```

Example 3: Combining Excel reading with a file upload

<figure><img src="/files/PbyUKqKJcXm9BiQmDfI3" alt=""><figcaption><p>Uploads an .xlsx file, saves it as a base64 buffer, and feeds it to the <code>readXlsx</code> function.</p></figcaption></figure>

### `readXlsxCells`

Reads the values of one or more specific cells from an Excel sheet.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>fileInput</code></td><td>The path to the <code>.xlsx</code> file or a base64 encoded string of the file content.</td><td>string</td></tr><tr><td><code>cellAddresses</code></td><td>A single cell address (such as <code>'B5'</code>) or an array of addresses (such as <code>['A1', 'C5']</code>).</td><td>string or array</td></tr><tr><td><code>sheetIdentifier</code></td><td>The name (such as <code>'Sales'</code>) or zero-based index (<code>0</code>) of the sheet. Default targets the first sheet.</td><td>string or integer</td></tr></tbody></table>

#### Example

```yaml
# fileInput
/path/to/report.xlsx
# cellAddresses
['B2', 'D5']
# sheetIdentifier
'Summary'
```

#### Output

Returns the cell value, or an array of values when you provide multiple addresses (such as `['Total Revenue', 15000]`). Empty or non-existent cells return no value. Throws an error if the file or sheet is not found.

### `writeXlsx`

Writes an array of JSON objects to a new Excel file.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>data</code></td><td></td><td>The array of JSON objects to write. This array must not be empty.</td><td>array</td></tr><tr><td><code>filePath</code></td><td></td><td>The path where the new <code>.xlsx</code> file is saved.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>sheetName</code></td><td>The name for the worksheet. Default <code>Sheet1</code>.</td><td>string</td></tr><tr><td></td><td><code>headers</code></td><td>An array of strings used as the header row. Default uses the keys of the first data object.</td><td>array</td></tr></tbody></table>

#### Example

```yaml
# data
[
  { "product": "Widget", "quantity": 10, "price": 19.99 },
  { "product": "Gadget", "quantity": 5, "price": 49.95 }
]
# filePath
/path/to/new_report.xlsx
# options
sheetName: 'Inventory'
```

#### Output

Returns nothing on success. Throws an error on empty data, an invalid path, or a failed write.

## Other document formats

### `readPdf`

Reads a PDF file and extracts its text content and metadata.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filename</code></td><td>The path to the <code>.pdf</code> file.</td><td>string</td></tr></tbody></table>

#### Output

Returns an object containing `text` (the full text content), `numpages`, `numrender`, and `info` (metadata):

```json
{
  "numpages": 2,
  "numrender": 2,
  "info": {
    "PDFFormatVersion": "1.7",
    "Title": "My Annual Report",
    "Author": "John Doe",
    "Creator": "Microsoft® Word for Office 365",
    "CreationDate": "D:20250822120200Z"
  },
  "metadata": null,
  "text": "\n\nPage 1 Content\n\nThis is the first paragraph of the annual report...\n\n",
  "version": "1.10.100"
}
```

### `readXml`

Reads an XML file and converts it into a JSON object.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filename</code></td><td></td><td>The path to the <code>.xml</code> file.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>attrkey</code></td><td>The key used for XML attributes. Default <code>_attr</code>.</td><td>string</td></tr><tr><td></td><td><code>explicitArray</code></td><td>If false, single-element arrays convert to a single object. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>mergeAttrs</code></td><td>If true, merges attributes into their parent object instead of a separate <code>attrkey</code> object.</td><td>boolean</td></tr><tr><td></td><td><code>explicitRoot</code></td><td>If false, the root XML element is excluded from the result.</td><td>boolean</td></tr></tbody></table>

All other [xml2js](https://www.npmjs.com/package/xml2js) parser options pass through directly.

#### Output

Returns a JSON representation of the XML content.

### `readDocx`, `readPptx`, `readHtml`, `readTxt`, `readMd`

These functions read their respective file types and extract the plain text content.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filename</code></td><td></td><td>The path to the file.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>preserveLineBreaks</code></td><td>Maintains line breaks from the original document. Default true.</td><td>boolean</td></tr></tbody></table>

All other [textract](https://www.npmjs.com/package/textract#configuration) options pass through directly.

#### Output

Returns the plain text content of the file as a string.


# GraphQL

The GraphQL connector interacts with GraphQL APIs. It provides a single static function to send queries or mutations to an endpoint and retrieve the results. All functions in this class are static and execute without an instance configuration.

### `request`

Sends a query or a mutation to a GraphQL API endpoint.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td>The endpoint URL of the GraphQL API.</td><td>string</td></tr><tr><td><code>document</code></td><td>The GraphQL query or mutation, written in standard GraphQL syntax.</td><td>string</td></tr><tr><td><code>variables</code></td><td>Optional variables required by the document.</td><td>object</td></tr><tr><td><code>headers</code></td><td>Optional request headers as key-value pairs, commonly used for authentication.</td><td>object</td></tr></tbody></table>

{% hint style="info" %}
Right-click the `headers` input and mark it as a secret to mask tokens or credentials.
{% endhint %}

#### Examples

Example 1: Simple query

This queries a list of movies.

```yaml
# url
https://api.example.com/graphql
# document
query {
  movies {
    id
    title
    releaseYear
  }
}
```

Example 2: Query with variables

This fetches a single movie by its ID, passed as a variable.

```yaml
# url
https://api.example.com/graphql
# document
query getMovieById($movieId: ID!) {
  movie(id: $movieId) {
    title
    director {
      name
    }
  }
}
# variables
movieId: "123"
```

Example 3: Mutation

This creates a new movie.

```yaml
# url
https://api.example.com/graphql
# document
mutation createMovie($title: String!, $year: Int!) {
  createMovie(title: $title, releaseYear: $year) {
    id
    title
  }
}
# variables
title: My New Movie
year: 2025
```

Example 4: Query with authentication

This sends an `Authorization` header with a Bearer token.

```yaml
# url
https://api.example.com/graphql
# document
query {
  myPrivateData {
    secretInfo
  }
}
# headers
Authorization: Bearer my-secret-auth-token
```

#### Output

Returns the data payload from the GraphQL API. Throws an error if the request fails or the API returns execution errors.


# GPIO counter

The GPIO counter counts digital pulses on a Raspberry Pi's GPIO pins. It interprets signals from sensors (such as inductive proximity sensors, light barriers, or rotary encoders) to track production counts, machine cycles, or flow rates.

Beyond counting, the class monitors the time interval between pulses to automatically determine whether a machine or process is running or stopped. It offers two operation modes:

1. average mode (default): Detects a stop when the time between pulses exceeds the running average by a configurable factor. This adapts dynamically to the speed of the machine.
2. target mode: Detects a stop when the time between pulses exceeds a fixed target interval plus a defined tolerance. Use this for processes with strict cycle times. Target mode is active when both `targetInterval` and `deviation` are set.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can interact with a physical pin, though it includes static utilities for hardware and pin detection.

{% hint style="warning" %}

#### Hardware requirement

This class requires a Raspberry Pi 4 or 5. If no compatible hardware is detected, the class automatically falls back to a simulation mode, letting you test your logic with the `simulatePulse` function.
{% endhint %}

## State machine

The counter operates on an internal state machine. Understanding the states helps with debugging and predicting behavior in production.

<figure><img src="/files/RZ5lQKbaNu1vaVtRtYX5" alt=""><figcaption></figcaption></figure>

### States

* `initialized`: The starting state after `create` or `reset`. The counter remains idle while waiting for the first signal, and no watchdog is active.
* `counting`: The active state. The counter registers pulses, calculates averages, and runs the auto-stop watchdog.
* `stopped`: The process has finished or paused. The counter enters this state automatically when the pulse interval becomes too long, or manually when you call `stop`. The current count is preserved.
* `rebooted`: The counter restored a persisted count after a restart. Pulses are ignored in this state. Call `start` to resume counting.
* `ended`: A terminal state entered via `end`. No further counts are registered and no auto-restart occurs until you call `reset`.

### Transitions

* Auto-start (`initialized` → `counting`): The first pulse on the GPIO pin starts the counter automatically.
* Auto-stop (`counting` → `stopped`): The time since the last pulse exceeded the limit calculated from `stopFactor` or `targetInterval`. This indicates the machine has stopped.
* Continue (`stopped` → `counting`): With `continueAfterStop` set to true, a new pulse automatically resumes counting.
* Manual control: `start` forces `counting`, `stop` forces `stopped`, `end` forces `ended`, and `reset` returns the counter to `initialized`.

### Persistence across restarts

The counter continuously persists its count and averages to a state file on disk. When you create an instance and a state file for that GPIO pin already exists, the connector restores the data and shifts the state to `rebooted`. This prevents data loss during a power outage or an App restart.

## Static functions

These functions manage hardware resources before you create a counter instance.

### `isAccessible`

Checks whether compatible GPIO hardware (Raspberry Pi 4 or 5) is accessible on the current system. Use this for feature detection to avoid errors on unsupported devices.

#### Parameters

None.

#### Output

Returns `true` if compatible hardware is detected, or `false` if it is not.

### `getPinConsumer`

Retrieves the name of the process that currently holds a specific GPIO pin. This helps diagnose resource conflicts when a pin is busy.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>gpio</code></td><td>The BCM pin number to check.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# gpio
17
```

#### Output

Returns a string containing the consumer name (such as `'gpiod'`), or `null` if the pin is free or the system runs in simulation mode.

### `isPinFree`

Checks whether a specific GPIO pin is currently free to use.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>gpio</code></td><td>The BCM pin number to check.</td><td>integer</td></tr></tbody></table>

#### Output

Returns `true` if the pin has no active consumer, or `false` if it does.

### `release`

Forcefully releases a specific GPIO pin if an internal driver instance holds it. Use this to recover pins that were not properly disposed of.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>gpio</code></td><td>The BCM pin number to release.</td><td>integer</td></tr></tbody></table>

#### Output

Returns `true` if the pin was found and released, or `false` if it was not.

## Instance and control

### `create`

Creates a counter instance, initializes the hardware connection or simulation, and configures the counting logic. Providing both `targetInterval` and `deviation` activates target mode; otherwise, the counter runs in average mode.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>gpio</code></td><td>The BCM pin number connected to the sensor.</td><td>integer</td></tr><tr><td></td><td><code>pullUpDown</code></td><td>Resistor configuration: <code>none</code>, <code>pullup</code>, or <code>pulldown</code>. Default <code>none</code>.</td><td>string</td></tr><tr><td></td><td><code>edge</code></td><td>The signal edge to count: <code>rising</code>, <code>falling</code>, or <code>both</code>. Default <code>rising</code>.</td><td>string</td></tr><tr><td></td><td><code>debounceTimeout</code></td><td>Debounce time in milliseconds to prevent false counts from noisy signals. Default 10.</td><td>integer</td></tr><tr><td></td><td><code>activeLow</code></td><td>If true, inverts the logic (useful if your sensor outputs 0 when active). Default false.</td><td>boolean</td></tr><tr><td></td><td><code>minCount</code></td><td>The minimum number of pulses required before the auto-stop watchdog activates. Default 5.</td><td>integer</td></tr><tr><td></td><td><code>continueAfterStop</code></td><td>If true, the counter automatically resumes counting when a new pulse arrives after a stop. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>stopFactor</code></td><td>Average mode only: The multiplier applied to the average interval to trigger a stop. Default 2.0.</td><td>number</td></tr><tr><td></td><td><code>targetInterval</code></td><td>Target mode only: The expected cycle time in seconds.</td><td>number</td></tr><tr><td></td><td><code>deviation</code></td><td>Target mode only: The allowed deviation in percent (0 to 100) before a pulse counts as too late.</td><td>number</td></tr></tbody></table>

#### Examples

Example 1: Average mode

This counter stops when a pulse takes more than 2.5 times the current average interval.

```yaml
# options
gpio: 17
pullUpDown: pullup
stopFactor: 2.5
minCount: 10
```

Example 2: Target mode

This counter expects a pulse every 5 seconds. It detects a stop when a pulse takes longer than 5.5 seconds (5 seconds plus 10 percent deviation).

```yaml
# options
gpio: 22
targetInterval: 5
deviation: 10
```

#### Output

Returns the name of the created instance.

### `start`

Manually starts the counting process. The counter normally starts automatically with the first pulse; use this function to force the `counting` state and arm the watchdog before a signal arrives, or to resume counting from the `rebooted` state. This call has no effect while the counter is already counting or in the `ended` state.

#### Parameters

None.

#### Output

Returns nothing.

### `stop`

Manually stops the counting process. This transitions the counter to the `stopped` state and cancels the watchdog while preserving the current count. This call has no effect unless the counter is actively counting.

#### Parameters

None.

#### Output

Returns nothing.

### `end`

Forces the counter into the terminal `ended` state. No further pulses are counted and no auto-restart occurs until you call `reset`. Use this to close a production session definitively.

#### Parameters

None.

#### Output

Returns nothing.

### `reset`

Resets the counter to its initial state by setting the count to 0, clearing all averages, and returning the state to `initialized`. You can optionally pass configuration parameters to update the counting logic during the reset.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>minCount</code></td><td>New minimum count parameter.</td><td>integer</td></tr><tr><td></td><td><code>stopFactor</code></td><td>New stop factor value (average mode).</td><td>number</td></tr><tr><td></td><td><code>targetInterval</code></td><td>New target interval measured in seconds (target mode).</td><td>number</td></tr><tr><td></td><td><code>deviation</code></td><td>New allowed deviation in percent (target mode).</td><td>number</td></tr><tr><td></td><td><code>continueAfterStop</code></td><td>Whether to resume counting automatically when a new pulse arrives after a stop.</td><td>boolean</td></tr></tbody></table>

#### Example

```yaml
# options
stopFactor: 1.5
```

#### Output

Returns nothing.

### `dispose`

Releases the hardware resources by freeing the GPIO pin and removes all listeners. Call this function when the counter is no longer needed to prevent hardware conflicts.

#### Parameters

None.

#### Output

Returns nothing.

### `delete`

Removes the counter instance.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To count on that pin again, you must trigger `create` anew.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Data and events

### `onCount`

Registers a callback that fires every time a valid pulse is counted. This serves as the primary method for receiving data from the counter.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>callback</code></td><td>Callback that fires on each count. Delivers an object containing metrics like total count and interval delta.</td><td>callback</td></tr></tbody></table>

#### Example

```yaml
# callback
<callback>
```

The callback delivers a JSON object matching this structure:

```json
{
  "count": 125,
  "exceededTargetCount": 0,
  "avgInterval": 1500.5,
  "delta": 1498,
  "timestamp": 1715605000123,
  "gpio": 17
}
```

The `avgInterval` property tracks the running average time between pulses in milliseconds, while `delta` measures the exact time elapsed since the previous pulse in milliseconds.

#### Output

Returns nothing.

### `onStateChange`

Registers a callback that fires whenever the counter's state changes, such as from `counting` to `stopped`.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>callback</code></td><td>Callback that fires on state changes. Delivers an object containing the new and previous states.</td><td>callback</td></tr></tbody></table>

#### Example

```yaml
# callback
<callback>
```

The callback delivers a JSON object matching this structure:

```json
{
  "state": "stopped",
  "previousState": "counting",
  "count": 125,
  "exceededTargetCount": 0,
  "timestamp": 1715605005000
}
```

#### Output

Returns nothing.

### `simulatePulse`

Manually simulates an input pulse. Use this to test your application logic away from the physical hardware. This function only works in simulation mode; real hardware ignores the call and logs a warning.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>value</code></td><td>The signal value to simulate. Default 1.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# value
1
```

#### Output

Returns nothing. The simulated pulse routes directly through the listener registered with `onCount`.

### `getCount`

Retrieves the current total count.

#### Parameters

None.

#### Output

Returns an integer representing the number of pulses counted so far.

### `getExceededTargetCount`

Retrieves how often the pulse interval exceeded the configured target time. This function applies to target mode only.

#### Parameters

None.

#### Output

Returns an integer representing the total number of exceeded targets.

### `getState`

Retrieves the current state of the counter.

#### Parameters

None.

#### Output

Returns a string representing the current state: `initialized`, `counting`, `stopped`, `rebooted`, or `ended`.

### `getAverageInterval`

Retrieves the current running average time between pulses.

#### Parameters

None.

#### Output

Returns a number representing the average interval in milliseconds.

### `getData`

Retrieves a full metrics snapshot of the counter's current data.

#### Parameters

None.

#### Output

Returns a JSON snapshot containing the counter variables:

```json
{
  "state": "counting",
  "count": 500,
  "exceededTargetCount": 0,
  "avgInterval": 1200.5,
  "targetInterval": 1.2
}
```

### `getConfiguration`

Retrieves the current configuration parameters of the instance.

#### Parameters

None.

#### Output

Returns a JSON object detailing the configuration fields:

```json
{
  "minCount": 5,
  "stopFactor": 2.0,
  "targetInterval": null,
  "deviation": null,
  "continueAfterStop": true
}
```


# Heidenhain DNC

Please [reach out to us](mailto:support@heisenware.com) for this advanced integration.


# Heidenhain OPC UA

The Heidenhain OPC UA connector interacts with Heidenhain CNC machine controls via OPC UA. It covers the entire workflow, from the initial secure certificate exchange to reading machine data and managing files on the control's `TNC:` file system.

This connector wraps the generic [OPC UA Client](/app-builder/build-backend/functions/connectors/opc-ua-client) and pre-configures it for Heidenhain requirements, utilizing a `SignAndEncrypt` connection with `Basic256Sha256` and certificate-based user authentication.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can interact with a machine.

See the [Connect Heidenhain CNC with OPC UA Support tutorial](/tutorials/integration-guides/connect-heidenhain-cnc-with-opc-ua-support) for step-by-step instructions.

## One-time secure setup

Heidenhain machines require a certificate exchange before the first connection. The connector automates this process in three steps:

{% stepper %}
{% step %}

### Prepare

Trigger `prepareOpcUaAssistant`. This creates the local client certificates and transfers them to the machine via SSH.
{% endstep %}

{% step %}

### Run the OPC UA Assistant

Run the OPC UA Assistant on the machine's control panel. Import the client certificates from `tnc://heisenware/import` and export the server certificates to `tnc://heisenware/export`.
{% endstep %}

{% step %}

### Finalize

Trigger `finalizeOpcUaAssistant`. This retrieves the server certificates from the machine via SSH and installs them into the local trust store. The client is now ready to connect.
{% endstep %}
{% endstepper %}

## Setup and connection

### `showDefaultMappings`

Returns the default internal mappings of common Heidenhain data points to their OPC UA `nodeId` values or browse paths. This helps identify which nodes high-level functions like `getOperatingMode` access.

#### Parameters

None.

#### Output

Returns a JSON object mapping human-readable names to OPC UA addresses:

```json
{
  "operatingMode": "/0:Objects/1:HEIDENHAIN NC/1:Machine/2:Channels/1:0/2:OperatingMode",
  "feedOverride": "/0:Objects/1:HEIDENHAIN NC/1:Machine/2:Channels/1:0/2:FeedOverride",
  "manufacturer": "ns=1;i=52004"
}
```

### `create`

Creates a connection instance for a specific Heidenhain machine. Use the machine's SSH credentials for the certificate exchange.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>machineIpAddress</code></td><td>The IP address or hostname of the Heidenhain machine.</td><td>string</td></tr><tr><td></td><td><code>machineUser</code></td><td>The SSH username for the machine. Default <code>user</code>.</td><td>string</td></tr><tr><td></td><td><code>machinePassword</code></td><td>The SSH password for the machine. Default <code>user</code>.</td><td>string</td></tr><tr><td></td><td><code>mappings</code></td><td>Optional overrides for the default OPC UA mappings.</td><td>object</td></tr></tbody></table>

{% hint style="info" %}
Right-click the `options` input and mark it as a secret to mask the password.
{% endhint %}

#### Example

```yaml
# options
machineIpAddress: 192.168.1.50
machineUser: heidenhain_user
machinePassword: my_secret_password
```

#### Output

Returns the name of the created instance.

### `prepareOpcUaAssistant`

The first step of the one-time secure setup. Creates the necessary local client certificates and transfers them to the Heidenhain machine via SSH. Afterwards, complete the exchange using the OPC UA Assistant on the machine's control panel.

#### Parameters

None.

#### Output

Returns a string containing instructions and the folder paths to use in the Heidenhain OPC UA Assistant on the machine control.

### `finalizeOpcUaAssistant`

The final step of the one-time secure setup. After the OPC UA Assistant on the machine has exported the server certificates, this function retrieves them via SSH and installs them into the local trust store.

#### Parameters

None.

#### Output

Returns a confirmation string indicating that the certificate exchange is complete and the client is ready to connect.

### `connect`

Establishes a secure OPC UA connection to the Heidenhain machine using the previously exchanged certificates.

#### Parameters

None.

#### Output

Returns `true` on a successful connection.

### `disconnect`

Closes the OPC UA session and disconnects from the machine.

#### Parameters

None.

#### Output

Returns `true` on a successful disconnection.

### `isConnected`

Checks whether the client has an active connection to the machine.

#### Parameters

None.

#### Output

Returns `true` if connected, or `false` if disconnected.

### `getMachineIpAddress`

Returns the IP address of the machine the instance was configured with.

#### Parameters

None.

#### Output

Returns the configured machine IP address string.

### `showMappings`

Returns the OPC UA mappings the instance currently uses, including any overrides provided at creation. Compare with the static `showDefaultMappings`, which shows the built-in defaults.

#### Parameters

None.

#### Output

Returns a JSON object mapping human-readable names to OPC UA addresses.

### `delete`

Removes the instance and closes the connection.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration, but not the exchanged certificates. To communicate with the machine again, you must trigger `create` and `connect` anew.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Machine data

These functions read common Heidenhain data points. None of them take parameters. `showDefaultMappings` reveals which OPC UA nodes they access.

### `getOperatingMode`

Reads the current NC operating mode.

#### Output

Returns a string representing the mode (such as `Manual`, `Automatic`, or `Handwheel`).

### `getFeedOverride`

Reads the current feed override value.

#### Output

Returns a number representing the feed override percentage.

### `getSpeedOverride`

Reads the current spindle speed override value.

#### Output

Returns a number representing the speed override percentage.

### `getRapidOverride`

Reads the current rapid speed override value.

#### Output

Returns a number representing the rapid override percentage.

### `getCutterLocation`

Reads the current X, Y, and Z coordinates of the tool tip.

#### Output

Returns an array of numbers `[X, Y, Z]`.

### `getToolInfo`

Provides information about the currently active tool.

#### Output

Returns an object containing the tool's `databaseId`, `identifier`, and `name`.

### `getProgramInfo`

Provides information about the currently running NC program.

#### Output

Returns an object containing details such as `currentCall`, `executionStack`, `name`, `fileNodeId`, and the program `currentState`.

### `getControlInfo`

Provides general information about the machine's control unit.

#### Output

Returns an object containing the `manufacturer`, `model`, `ncVersion`, and `ncKernel`.

### `getOperatingTimeInfo`

Provides information about machine and control operating times.

#### Output

Returns an object containing `controlUpTime`, `machineUpTime`, and `programExecutionTime`.

### `getStateInfo`

Provides information about the machine's current state.

#### Output

Returns an object containing the `currentState` and `lastTransition` of the machine's state machine.

### `getActiveErrors`

Retrieves a detailed list of all currently active errors on the machine.

#### Output

Returns an object where each key is an error ID and each value contains detailed information about that error (such as `action`, `cause`, and `text`).

## TNC file system

These functions interact with the machine's `TNC:` file system.

### `browseTncDirectory`

Browses the root of the machine's `TNC:` file system non-recursively.

#### Parameters

None.

#### Output

Returns an array of objects, each containing a `name` and `nodeId` for a file or folder.

### `readTncFile`

Reads a file from the `TNC:` directory.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filePath</code></td><td></td><td>The path to the file using forward slashes (such as <code>programs/main.h</code>).</td><td>string</td></tr><tr><td><code>options</code></td><td><code>encoding</code></td><td>The encoding of the returned content (such as <code>ascii</code> or <code>base64</code>). Default <code>utf8</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns the file content as a string in the requested encoding, utf8 by default. Note that this differs from the generic [OPC UA client](/app-builder/build-backend/functions/connectors/opc-ua-client#readfile), whose `readFile` defaults to base64, because NC programs are text files.

#### Example

```yaml
# filePath
programs/main.h
```

### `writeTncFile`

Writes a new file to the `TNC:` directory.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>newFileName</code></td><td>The name of the file to create, including its path (such as <code>setups/tool_list.txt</code>).</td><td>string</td></tr><tr><td><code>content</code></td><td>The data to write, either as a local file path or a base64 string.</td><td>string</td></tr></tbody></table>

#### Output

Returns the `nodeId` of the newly created file.

### `deleteTncFile`

Deletes a file from the `TNC:` directory.

{% hint style="danger" %}

#### Irreversible action

Deleting a file permanently removes it from the machine's control. This action cannot be undone.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>fileName</code></td><td>The name of the file to delete, including its path.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true` when the file is successfully deleted, or `false` if the deletion fails.

## Generic OPC UA functions

These functions pass directly through to the underlying [OPC UA client](/app-builder/build-backend/functions/connectors/opc-ua-client) for generic OPC UA operations when the specialized Heidenhain functions are not sufficient. Parameters and outputs are identical to the OPC UA client documentation: `browseObjects`, `callMethod`, `deleteFile`, `readFile`, `readNode`, `readVariable`, `writeFile`, and `writeVariable`. One difference: `readFile` defaults to `utf8` encoding here instead of base64.


# HTTP / REST

The HTTP / REST connector executes HTTP requests and interacts with REST APIs. It supports standard HTTP methods and works in two modes: as standalone static utilities for immediate, one-off calls, or as a persistent instance client configured with uniform base URLs, shared header contexts, and automated authentication handlers.

This connector supports mixed execution options, meaning you can call static functions directly or use [instance creation](/app-builder/build-backend/functions/connectors#instance-creation). See [Tips and tricks](#tips-and-tricks) for the error behavior and a shortcut for passing query parameters.

## Static functions

### `get`

Performs an HTTP GET request to fetch a resource from a remote server.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The full destination URL of the endpoint.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters sent as key-value pairs.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers included with the request.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr><tr><td></td><td><code>auth</code></td><td>Basic authentication payload containing <code>username</code> and <code>password</code> strings.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# url
https://api.open-meteo.com/v1/forecast
# options
params:
  latitude: 53.5507
  longitude: 9.993
  hourly:
    - temperature_2m
    - rain
    - cloud_cover
  forecast_days: 1
```

#### Output

Returns the parsed data payload from the server, typically as a JSON object, array, or raw string.

### `post`

Performs an HTTP POST request to submit data payloads to a remote host.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The full destination URL of the endpoint.</td><td>string</td></tr><tr><td><code>data</code></td><td></td><td>The payload body to deliver to the server. Accepts text, objects, or arrays.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters sent as key-value pairs.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers included with the request.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr><tr><td></td><td><code>auth</code></td><td>Basic authentication configuration.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# url
https://api.example.com/blogs
# data
title: New blog post
content: This is the verified body text payload.
```

#### Output

Returns the full response object from the server, including `data`, `status`, and `headers`.

### `put`

Performs an HTTP PUT request to update or completely replace a target resource.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The full destination URL of the endpoint.</td><td>string</td></tr><tr><td><code>data</code></td><td></td><td>The payload body to deliver to the server.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr><tr><td></td><td><code>auth</code></td><td>Basic authentication configuration.</td><td>object</td></tr></tbody></table>

#### Output

Returns the full response object from the server, including `data`, `status`, and `headers`.

### `patch`

Performs an HTTP PATCH request to apply partial modifications to a resource.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The full destination URL of the endpoint.</td><td>string</td></tr><tr><td><code>data</code></td><td></td><td>The partial update data applied to the resource.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr><tr><td></td><td><code>auth</code></td><td>Basic authentication configuration.</td><td>object</td></tr></tbody></table>

#### Output

Returns the full response object from the server, including `data`, `status`, and `headers`.

### `delete`

Performs an HTTP DELETE request to remove a specific resource from the server.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The full destination URL of the resource to delete.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr><tr><td></td><td><code>auth</code></td><td>Basic authentication configuration.</td><td>object</td></tr></tbody></table>

#### Output

Returns the full response object from the server, including `data`, `status`, and `headers`.

### `head`

Performs an HTTP HEAD request to fetch meta headers without reading the document response body.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The full destination URL of the endpoint.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr><tr><td></td><td><code>auth</code></td><td>Basic authentication configuration.</td><td>object</td></tr></tbody></table>

#### Output

Returns the full response object. For HEAD requests, the `data` body is empty and the relevant information sits in `headers`.

### `options`

Performs an HTTP OPTIONS request to query the permissible communication methods allowed by the server.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The full destination URL of the endpoint.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr><tr><td></td><td><code>auth</code></td><td>Basic authentication configuration.</td><td>object</td></tr></tbody></table>

#### Output

Returns the full response object. The allowed communication options typically sit in the `headers` (such as `Allow`).

## Instance client

### `create`

Constructs a reusable, persistent HTTP client instance configured with shared authentication schemes, automated token management, and standardized relative path routing.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>baseUrl</code></td><td></td><td>The base URL string prepended automatically to all subsequent partial relative paths.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>headers</code></td><td>Default headers sent with every request.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>The default request timeout in milliseconds for all requests.</td><td>integer</td></tr><tr><td></td><td><code>username</code></td><td>The username for default HTTP basic authentication.</td><td>string</td></tr><tr><td></td><td><code>password</code></td><td>The password for default HTTP basic authentication.</td><td>string</td></tr><tr><td></td><td><code>token</code></td><td>The authentication token.</td><td>string</td></tr><tr><td></td><td><code>isBearer</code></td><td>If true, sends the token as a bearer token in the <code>Authorization</code> header. Takes precedence over <code>authHeader</code>.</td><td>boolean</td></tr><tr><td></td><td><code>authHeader</code></td><td>Sends the token in a custom HTTP header with this name.</td><td>string</td></tr><tr><td></td><td><code>authParameter</code></td><td>Sends the token as a URL query parameter with this name on every request.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# baseUrl
https://api.my-fake-rest-server.com
# options
username: gerhard@gmx.de
password: Waltraud_1957
token: '194307'
authHeader: X-Access-Id
```

#### Output

Returns the name of the created instance.

### `get`

Performs an HTTP GET request utilizing the pre-configured settings of the instance client.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The relative path string (such as <code>/blogs</code>) appended to the base URL, or an absolute link.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters sent as key-value pairs.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP header elements overriding instance defaults.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# url
/blogs
# options
params:
  category: tech
```

#### Output

Returns the parsed data payload from the server, typically as a JSON object, array, or raw string.

### `post`

Performs an HTTP POST request utilizing the pre-configured settings of the instance client.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The relative path string or absolute endpoint link.</td><td>string</td></tr><tr><td><code>data</code></td><td></td><td>The structured body data block submitted to the remote server.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers overriding defaults.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# url
/blogs
# data
title: New post
```

#### Output

Returns the full response object from the server, including `data`, `status`, and `headers`.

### `put`

Performs an HTTP PUT request utilizing the pre-configured settings of the instance client.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The relative path string or absolute link.</td><td>string</td></tr><tr><td><code>data</code></td><td></td><td>The data payload transferred to the server destination.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the full response object from the server, including `data`, `status`, and `headers`.

### `patch`

Performs an HTTP PATCH request utilizing the pre-configured settings of the instance client.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The relative path string or absolute link.</td><td>string</td></tr><tr><td><code>data</code></td><td></td><td>The partial modification payload.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the full response object from the server, including `data`, `status`, and `headers`.

### `delete`

Performs an HTTP DELETE request utilizing the pre-configured settings of the instance client.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The relative path string or absolute link targeting a resource.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the full response object from the server, including `data`, `status`, and `headers`.

### `head`

Performs an HTTP HEAD request utilizing the pre-configured settings of the instance client.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The relative path string or absolute link.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the full response object. For HEAD requests, the `data` body is empty and the relevant information sits in `headers`.

### `options`

Performs an HTTP OPTIONS request utilizing the pre-configured settings of the instance client.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The relative path string or absolute link.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>URL query parameters.</td><td>object</td></tr><tr><td></td><td><code>headers</code></td><td>Custom HTTP headers.</td><td>object</td></tr><tr><td></td><td><code>timeout</code></td><td>Request timeout in milliseconds.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the full response object. The allowed communication options typically sit in the `headers` (such as `Allow`).

## Tips and tricks

### Passing query parameters directly

You can pass a flat object straight into `options`. When it contains none of the keys `params`, `headers`, `timeout`, or `auth`, the connector interprets the entire object as the `params` query parameters.

### Error behavior

Failed requests throw an error. When the server responds with an error status, the error message contains the status code and status text (such as `404 Not Found`), and the response body is attached as the error cause. Network-level failures (such as an unreachable host or a timeout) throw the original error.


# Hydra MIP

The Hydra MIP connector communicates with the MPDV Hydra Manufacturing Integration Platform (MIP). It abstracts the underlying API into a unified layer, supporting both legacy Hydra 8 dialog transactions and modern MIP 2.0 Shop Floor Connectivity Services (SCS). The connector automatically detects the backend version at runtime and routes requests dynamically.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can manage sessions or execute transactions against a specific MIP server.

## Connection and lifecycle

### `create` (instance)

Creates a client instance configured to communicate with a specific MIP server.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>url</code></td><td>The endpoint URL of the target MIP server.</td><td>string</td></tr><tr><td></td><td><code>username</code></td><td>The username used for authentication.</td><td>string</td></tr><tr><td></td><td><code>password</code></td><td>The password used for authentication.</td><td>string</td></tr><tr><td></td><td><code>accessId</code></td><td>An 8-digit ID identifying the client application, left-padded with zeros if necessary.</td><td>string</td></tr><tr><td></td><td><code>rejectUnauthorized</code></td><td>Set to false to temporarily disable rejection of untrusted server certificates. Default true.</td><td>boolean</td></tr><tr><td><code>caPath</code></td><td></td><td>An optional absolute path to a root CA <code>.pem</code> file for internal TLS.</td><td>string</td></tr></tbody></table>

{% hint style="info" %}
Right-click the `options` input and mark it as a secret to mask the password.
{% endhint %}

#### Example

```yaml
# options
url: https://my-mip-server.com:8080
username: myuser
password: mysecretpassword
accessId: '00123456'
```

#### Output

Returns the name of the created instance.

### `canCommunicate`

Checks whether communication with the MIP server is operational and authenticated.

#### Parameters

None.

#### Output

Returns `true` if communication succeeds, or `false` if it fails.

### `getMipVersion`

Retrieves the runtime strategy description of the connected backend.

#### Parameters

None.

#### Output

Returns `'Hydra X / MIP 2.0 (SCS)'` or `'Hydra 8 / MIP 1.x (Legacy)'`.

### `isMip2`

Determines if the current backend supports modern MIP 2.0 architectures.

#### Parameters

None.

#### Output

Returns `true` if the backend supports MIP 2.0, or `false` if it does not.

### `logout`

Terminates the open session on the MIP server and clears active cookies. Without an explicit logout, open sessions terminate automatically after 30 minutes.

#### Parameters

None.

#### Output

Returns `true` upon successful session termination, or `false` if it fails.

### `delete` (instance)

Removes the MIP client instance and its connection configuration. Not to be confused with [`delete` (record)](#delete-record), which removes a service record on the MIP server.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To communicate with the server again, you must trigger `create` anew.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Low-level service CRUD

### `getAllServices`

Lists all data-layer services registered on the connected server.

#### Parameters

None.

#### Output

Returns an array of service name strings.

### `create` (record)

Creates a new instance record for a given service type. Not to be confused with [`create` (instance)](#create-instance), which creates the connector instance.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>serviceName</code></td><td>The service name (such as <code>MDUnits</code>, <code>BOOperation</code>, or <code>BOPerson</code>).</td><td>string</td></tr><tr><td><code>data</code></td><td>The data payload for the creation transaction. Use <code>getCreateParameters</code> to look up mandatory attributes.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# serviceName
MDUnits
# data
unitsUnit: T
unitsClassification: Test
unitsDesignation: A fake test unit
```

#### Output

Returns `true` on success. Throws an error if the transaction fails.

### `read`

Queries records from a given service with options for filtering and field selection.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>serviceName</code></td><td></td><td>The service name.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>filter</code></td><td>Filters records based on specific criteria. Accepts a simple array like <code>['field', '=', 'val']</code>, an object like <code>{ field: 'val' }</code>, or nested arrays. MIP does not support OR logic.</td><td>any</td></tr><tr><td></td><td><code>fields</code></td><td>Restricts the evaluation to specific columns.</td><td>array</td></tr><tr><td></td><td><code>skipNull</code></td><td>When true, omits null attributes from the return value. Default false.</td><td>boolean</td></tr></tbody></table>

#### Example

```yaml
# serviceName
MDUnits
# options
filter: [unitsDigits, '>', 1]
fields: [unitsUnit, unitsDesignation]
skipNull: true
```

#### Output

Returns an array of parsed data objects matching the query.

### `update`

Modifies an existing service instance record.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>serviceName</code></td><td>The service name.</td><td>string</td></tr><tr><td><code>data</code></td><td>The data update block. This block must include the mandatory primary keys required to identify the row.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# serviceName
MDUnits
# data
unitsUnit: C
unitsClassification: Temp
unitsDesignation: Degree Celsius
```

#### Output

Returns `true` on a successful update. Throws an error if the operation fails.

### `delete` (record)

Removes an existing service instance record.

{% hint style="danger" %}

#### Irreversible action

This permanently deletes the service instance record from the server. You cannot undo this action.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>serviceName</code></td><td>The service name.</td><td>string</td></tr><tr><td><code>data</code></td><td>Mandatory identification payload required to resolve the specific instance.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# serviceName
MDUnits
# data
unitsUnit: T
unitsClassification: Test
```

#### Output

Returns `true` on a successful deletion. Throws an error if the operation fails.

### `execute`

Invokes a specific processing action on a target service.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>serviceName</code></td><td>The service name.</td><td>string</td></tr><tr><td><code>data</code></td><td>The parameters required for execution. Keys must match the service definition.</td><td>object</td></tr></tbody></table>

#### Output

Returns `true` on a successful execution. Throws an error if the action fails.

## Metadata inspection

### `getCreateParameters`

Queries the parameters needed to create records for a specified service.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>serviceName</code></td><td>The service name.</td><td>string</td></tr></tbody></table>

#### Output

Returns an object mapping camelCase attributes to their lowercase data types. Mandatory parameters include a `*` suffix.

### `getReadParameters`

Queries the schema parameters available for retrieval from a service.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>serviceName</code></td><td>The service name.</td><td>string</td></tr></tbody></table>

#### Output

Returns an object mapping readable camelCase fields to their lowercase data types.

### `getUpdateParameters`

Queries the schema guidelines for updating records inside a service.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>serviceName</code></td><td>The service name.</td><td>string</td></tr></tbody></table>

#### Output

Returns an object mapping updatable attributes to data types, with mandatory lookup attributes marked with a `*` suffix.

### `getExecuteParameters`

Queries the validation constraints needed for executing functions on a service.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>serviceName</code></td><td>The service name.</td><td>string</td></tr></tbody></table>

#### Output

Returns an object mapping functional input tags to data types.

### `getDeleteParameters`

Queries the minimal mandatory parameter requirements to delete a service instance.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>serviceName</code></td><td>The service name.</td><td>string</td></tr></tbody></table>

#### Output

Returns an object highlighting mandatory row identification fields.

### `getReadableFields`

Lists all column elements explicitly exposed as selectable output fields.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>serviceName</code></td><td>The service name.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of objects mapping selectable keys to their lowercase types.

## Order management (MIP-WO)

### `getOrders`

Fetches production orders and enriches them with active operations, BOM components, and allocated tools.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>filter</code></td><td>Filters the orders to retrieve. Evaluates an array or object expression.</td><td>any</td></tr><tr><td></td><td><code>fields</code></td><td>Appends custom attributes to the default return payload.</td><td>array</td></tr><tr><td></td><td><code>includeOperations</code></td><td>Includes corresponding operations. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>includeComponents</code></td><td>Includes related component requirements. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>includeProductionResources</code></td><td>Includes related tool records. Default true.</td><td>boolean</td></tr></tbody></table>

#### Example

```yaml
# options
filter: { orderId: JR150702 }
includeOperations: false
fields: [ordertypeActive]
```

#### Output

Returns an array of complex order structures.

### `getOrder`

Fetches details for an isolated order instance.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>orderId</code></td><td></td><td>The unique order ID string.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>fields</code></td><td>Specifies explicit fields to fetch. If empty, all available fields return.</td><td>array</td></tr></tbody></table>

#### Example

```yaml
# orderId
'4711'
# options
fields: [orderId, orderDesignation, orderPlanStartTimestamp]
```

#### Output

Returns an order object, or `null` if the order is not found.

### `startOperation`

Registers an operation log-on transaction (Arbeitsgang anmelden).

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>orderId</code></td><td>The order identifier. Legacy acronym fallback: <code>anr</code>.</td><td>string</td></tr><tr><td></td><td><code>operationId</code></td><td>The operation identifier. Legacy acronym fallback: <code>avnr</code>.</td><td>string</td></tr><tr><td></td><td><code>workplaceId</code></td><td>The workplace or machine identifier. Legacy acronym fallback: <code>mnr</code>.</td><td>string</td></tr><tr><td></td><td><code>personId</code></td><td>The person identifier. Legacy acronym fallback: <code>pnr</code> or <code>usr</code>.</td><td>string</td></tr><tr><td></td><td><code>cardId</code></td><td>The card identifier. Legacy acronym fallback: <code>knr</code>.</td><td>string</td></tr><tr><td></td><td><code>batchId</code></td><td>The batch identifier. Legacy acronym fallback: <code>cnr</code>.</td><td>string</td></tr><tr><td></td><td><code>mst</code></td><td>The target machine status code (Legacy specific).</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# options
orderId: '0004990701'
operationId: '10'
workplaceId: '4560'
personId: '2998'
```

#### Output

Returns `true` on successful registration. Throws an error if the transaction fails.

### `finishOperation`

Finishes an operation (Arbeitsgang beenden/abmelden) and optionally posts produced quantities.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>orderId</code></td><td>The order identifier. Legacy acronym fallback: <code>anr</code>.</td><td>string</td></tr><tr><td></td><td><code>operationId</code></td><td>The operation identifier. Legacy acronym fallback: <code>avnr</code>.</td><td>string</td></tr><tr><td></td><td><code>workplaceId</code></td><td>The workplace or machine identifier. Legacy acronym fallback: <code>mnr</code>.</td><td>string</td></tr><tr><td></td><td><code>personId</code></td><td>The person identifier. Legacy acronym fallback: <code>pnr</code>.</td><td>string</td></tr><tr><td></td><td><code>yield</code></td><td>The produced good quantity. Legacy acronym fallback: <code>egrGut</code>.</td><td>integer</td></tr><tr><td></td><td><code>scrap</code></td><td>The produced scrap quantity. Legacy acronym fallback: <code>egrAus</code>.</td><td>integer</td></tr><tr><td></td><td><code>scrapReason</code></td><td>The reason code for scrap. Legacy acronym fallback: <code>eggAus</code>.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# options
orderId: '0004990701'
operationId: '10'
workplaceId: '4560'
yield: 100
scrap: 5
scrapReason: 1
```

#### Output

Returns `true` on success. Throws an error if the transaction fails.

### `interruptOperation`

Interrupts a registered operation (Arbeitsgang unterbrechen), for example for breaks or shift ends where the job is not yet complete. Optionally posts partial quantities.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>orderId</code></td><td>The order identifier. Legacy acronym fallback: <code>anr</code>.</td><td>string</td></tr><tr><td></td><td><code>operationId</code></td><td>The operation identifier. Legacy acronym fallback: <code>avnr</code>.</td><td>string</td></tr><tr><td></td><td><code>workplaceId</code></td><td>The workplace or machine identifier. Legacy acronym fallback: <code>mnr</code>.</td><td>string</td></tr><tr><td></td><td><code>personId</code></td><td>The person identifier. Legacy acronym fallback: <code>pnr</code>.</td><td>string</td></tr><tr><td></td><td><code>yield</code></td><td>The partial yield quantity. Legacy acronym fallback: <code>egrGut</code>.</td><td>integer</td></tr><tr><td></td><td><code>scrap</code></td><td>The partial scrap quantity. Legacy acronym fallback: <code>egrAus</code>.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# options
orderId: '0004990701'
workplaceId: '4560'
yield: 50
```

#### Output

Returns `true` on success. Throws an error if the transaction fails.

### `reportPartialQuantity`

Posts produced part quantities (Teilrückmeldung), including good parts and scrap, for an active operation.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>orderId</code></td><td>The order identifier. Legacy acronym fallback: <code>anr</code>.</td><td>string</td></tr><tr><td></td><td><code>operationId</code></td><td>The operation identifier. Legacy acronym fallback: <code>avnr</code>.</td><td>string</td></tr><tr><td></td><td><code>workplaceId</code></td><td>The workplace or machine identifier. Legacy acronym fallback: <code>mnr</code>.</td><td>string</td></tr><tr><td></td><td><code>personId</code></td><td>The person identifier. Legacy acronym fallback: <code>pnr</code>.</td><td>string</td></tr><tr><td></td><td><code>cardId</code></td><td>The card identifier. Legacy acronym fallback: <code>knr</code>.</td><td>string</td></tr><tr><td></td><td><code>yield</code></td><td>The produced good quantity. Legacy acronym fallback: <code>egrGut</code>.</td><td>integer</td></tr><tr><td></td><td><code>scrap</code></td><td>The produced scrap quantity. Legacy acronym fallback: <code>egrAus</code>.</td><td>integer</td></tr><tr><td></td><td><code>scrapReason</code></td><td>The reason code for scrap. Legacy acronym fallback: <code>eggAus</code>.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# options
orderId: 'AAA2100473100200'
workplaceId: '60610'
personId: '11111'
yield: 100
scrap: 2
scrapReason: 1
```

#### Output

Returns `true` on success. Throws an error if the transaction fails.

## Workplaces, resources, and personnel

### `getWorkplaces`

Reads workplaces and machines. This high-level convenience function applies default fields, associations, and filtering on top of the generic `read` function.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="200">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>filter</code></td><td>Additional user-defined filters.</td><td>any</td></tr><tr><td></td><td><code>fields</code></td><td>Restricts the evaluation to specific columns.</td><td>array</td></tr><tr><td></td><td><code>includeStatusAssignments</code></td><td>Includes corresponding status assignments. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>includeGroups</code></td><td>Includes corresponding capacity groups. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>skipNull</code></td><td>When true, omits null attributes from the return value. Default false.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns an array of workplace objects including identifiers, designations, and current status information.

### `getResources`

Reads resources such as tools, equipment, and gages. Without a `type`, the function returns all resources that are not workplaces.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>type</code></td><td>An optional specific resource type (such as <code>TOOL</code> or <code>GAGE</code>).</td><td>string</td></tr><tr><td></td><td><code>filter</code></td><td>Additional user-defined filters.</td><td>any</td></tr><tr><td></td><td><code>fields</code></td><td>Restricts the evaluation to specific columns.</td><td>array</td></tr><tr><td></td><td><code>skipNull</code></td><td>When true, omits null attributes from the return value. Default false.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns an array of resource objects matching the query.

### `getPersons`

Retrieves personnel details and aggregates data from multiple MIP-HR services into a single object per person, optionally enriched with qualifications and workplace assignments.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="200">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>filter</code></td><td>Filters for the person list.</td><td>any</td></tr><tr><td></td><td><code>fields</code></td><td>Specific fields to retrieve for the person.</td><td>array</td></tr><tr><td></td><td><code>includeQualifications</code></td><td>Includes assigned qualifications. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>includeAssignments</code></td><td>Includes current workplace assignments. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>includeClockingStatus</code></td><td>Includes live attendance data. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>skipNull</code></td><td>When true, omits null attributes from the return value. Default false.</td><td>boolean</td></tr></tbody></table>

#### Example

```yaml
# options
filter: { personLastname: Smith }
includeQualifications: true
includeAssignments: false
```

#### Output

Returns an array of person objects, or an empty array if no person matches.

## Dialogs and raw calls

### `runDialog`

Runs a named dialog with a set of key-value pairs.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>dialogName</code></td><td></td><td>The name of the dialog (such as <code>A_AN</code>).</td><td>string</td></tr><tr><td><code>options</code></td><td></td><td>The key-value parameters for the dialog. Add <code>dryRun: true</code> to receive the generated dialog string without sending it.</td><td>object</td></tr></tbody></table>

#### Output

Returns the raw dialog response of the MIP server, or the generated dialog string when `dryRun` is set.

### `rawServiceCall`

Executes a raw service call for advanced use cases. The parameters map directly to the MIP Service Interface specification.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The service URL to call (such as <code>/data/MDUnits/list</code>).</td><td>string</td></tr><tr><td><code>options</code></td><td><code>params</code></td><td>A list of filter parameter objects with <code>acronym</code>, <code>operator</code>, and <code>value</code>.</td><td>array</td></tr><tr><td></td><td><code>columns</code></td><td>The selected columns.</td><td>array</td></tr><tr><td></td><td><code>requestId</code></td><td>The request ID.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# url
/data/MDUnits/list
# options
params: [{ acronym: units.unit, operator: EQUAL, value: C }]
```

#### Output

Returns the raw response of the MIP server.

### `rawDialogCall`

Executes a raw dialog call by sending the complete dialog string.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>dialogString</code></td><td>The complete dialog string to send.</td><td>string</td></tr></tbody></table>

#### Output

Returns the raw response of the MIP server.


# Kuando Busylight

The Kuando Busylight connector controls Kuando Busylight status indicators. It changes the light's color and brightness, makes it blink or pulse, and plays the device's built-in sounds.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can control a physical unit, though it includes a static utility for device scanning. Because a Busylight is a physical USB device on your premises, this function typically executes inside an [Agent](/app-builder/build-backend/agents) installed on the local computer where the light is connected (see the [local connection scenario](/app-builder/build-backend/functions/connectors#local-connection-via-agent)).

## Device management

### `getDevices`

Scans the local system and lists all connected Busylight devices.

#### Parameters

None.

#### Output

Returns an array of device objects containing details about each connected Busylight.

### `create`

Creates an instance to control a specific Kuando Busylight and establishes a connection to it. To control multiple lights connected to the same computer, create one instance per device using its respective index.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>deviceIndex</code></td><td>The zero-based index of the device to control, selected from the array returned by <code>getDevices</code>. Default 0.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# deviceIndex
1
```

#### Output

Returns the name of the created instance.

### `getName`

Retrieves the model name of the connected device.

#### Parameters

None.

#### Output

Returns the device model name as a string (such as `Busylight Omega model 2`).

### `getTones`

Retrieves all available tone names supported by the connected device.

#### Parameters

None.

#### Output

Returns an array of strings containing the names of all playable tones.

### `delete`

Removes the instance and disconnects from the device.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To control the device again, you must trigger `create` anew.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Light and sound

### `setColor`

Turns on the light with a solid, continuous color.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>color</code></td><td>The desired color in any CSS-compatible format (such as <code>#ff0000</code>, <code>rgb(255, 0, 0)</code>, or <code>red</code>).</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# color
'#0000FF'
```

#### Output

Returns the raw result of the underlying device driver. The value is not meant for further processing.

### `pulse`

Fades the light in and out smoothly using the specified color.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>color</code></td><td>The color to pulse, provided in any CSS-compatible format.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# color
orange
```

#### Output

Returns the raw result of the underlying device driver. The value is not meant for further processing.

### `blink`

Flashes the light using the specified color and timing configuration.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>color</code></td><td>The color to blink, provided in any CSS-compatible format.</td><td>string</td></tr><tr><td><code>onDuration</code></td><td>The time in seconds the light stays on during each blink cycle. Default 0.5.</td><td>number</td></tr><tr><td><code>offDuration</code></td><td>The time in seconds the light stays off during each blink cycle. Default 0.3.</td><td>number</td></tr></tbody></table>

#### Example

```yaml
# color
red
# onDuration
0.2
# offDuration
0.2
```

#### Output

Returns the raw result of the underlying device driver. The value is not meant for further processing.

### `setLightIntensity`

Changes the brightness of the light. The new intensity applies immediately to the active light state and overrides the default for subsequent commands.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>value</code></td><td>The light intensity measured in percent (0 to 100).</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# value
50
```

#### Output

Returns nothing.

### `playTone`

Plays one of the device's built-in sounds once.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>name</code></td><td>The name of the tone to play, matching an item from the list returned by <code>getTones</code>.</td><td>string</td></tr><tr><td><code>volume</code></td><td>Optional volume level (0 to 10). If provided, this value also sets the new default volume. If omitted, the connector uses the last configured volume. Default 3.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# name
'Open Office'
```

#### Output

Returns the raw result of the underlying device driver. The value is not meant for further processing.

### `setToneVolume`

Sets the default volume for all sounds played by the device.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>value</code></td><td>The target volume level (0 to 10).</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# value
7
```

#### Output

Returns `true` once the volume is set.

### `alert`

Triggers a pre-configured alert sequence, combining a flashing red light and a tone to grab attention. The alert turns itself off automatically after a few seconds.

#### Parameters

None.

#### Output

Returns nothing.

### `off`

Switches off the light and any playing sound immediately.

#### Parameters

None.

#### Output

Returns the raw result of the underlying device driver. The value is not meant for further processing.


# Label printer

The label printer connector creates, manages, and prints labels on network-connected printers. It fills a template layout with dynamic variables, collects the generated labels into a batch, and sends the batch as raw text directly over a TCP connection, for example to a Zebra ZT411 UHF.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can interact with a printer.

## Instance and template

### `create`

Creates a label printer instance and sets the initial layout template string.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>template</code></td><td>The layout template string. Use <code>{{variableName}}</code> syntax to mark the fields that receive dynamic text.</td><td>string</td></tr></tbody></table>

#### Example

This example initializes an instance using a Zebra Programming Language (ZPL) template for a 4x6 inch label:

```yaml
# template
^XA^LL1218^PW812^FO50,50^A0N,50,50^FD{{product_name}}^FS^FO50,120^A0N,30,30^FDPart No: {{part_number}}^FS^XZ
```

#### Output

Returns the name of the created instance.

### `setTemplate`

Updates the template for an existing instance. Calling this function also clears all previously generated labels from the batch.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>template</code></td><td>The new template string.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# template
^XA^FO100,100^A0N,40,40^FD{{message}}^FS^XZ
```

#### Output

Returns the updated template string.

### `getTemplate`

Retrieves the template currently assigned to the instance.

#### Parameters

None.

#### Output

Returns the active template string.

### `delete`

Removes the instance, including its template and the current batch.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration and any unsent labels in the batch. To print again, you must trigger `create` anew.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Batch handling

### `addLabel`

Generates a single label by inserting the provided variables into the template placeholders and adds it to the batch.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>variables</code></td><td>An object where each key corresponds to a template placeholder name, without the curly brackets.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# variables
product_name: High-Torque Motor
part_number: HT-5000
```

#### Output

Returns the generated label string with all placeholders replaced. Throws an error if a template variable has no matching key in `variables`.

### `showBatch`

Returns all labels generated since the batch was last cleared.

#### Parameters

None.

#### Output

Returns a single string containing all generated labels, joined by line breaks.

### `getNumberOfLabels`

Retrieves how many labels the current batch contains.

#### Parameters

None.

#### Output

Returns an integer representing the number of labels in the batch.

### `removeDuplicates`

Removes duplicated labels from the current batch.

#### Parameters

None.

#### Output

Returns an integer representing the number of removed duplicates.

### `clearBatch`

Removes all generated labels from the current batch, starting a new, empty batch.

#### Parameters

None.

#### Output

Returns `true` upon successful clearing.

## Printing

### `sendBatchToPrinter`

Sends the current batch of labels to a network-connected printer over a raw TCP connection.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="200">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>ip</code></td><td></td><td>The IP address of the target printer.</td><td>string</td></tr><tr><td><code>port</code></td><td></td><td>The network port of the printer. Default 9100.</td><td>integer</td></tr><tr><td><code>options</code></td><td><code>removeDuplicates</code></td><td>When true, removes duplicated labels prior to printing. Default false.</td><td>boolean</td></tr></tbody></table>

#### Example

```yaml
# ip
192.168.1.123
# port
9100
```

#### Output

Returns `true` when the batch transmits successfully. Throws an error if the batch is empty, the connection fails, or the printer does not respond within 5 seconds.


# Modbus

The Modbus connector provides a unified interface for communicating with Modbus devices. It handles low-level data framing and supports the two primary industrial communication protocols:

* Modbus TCP: For devices connected over an Ethernet network.
* Modbus RTU: For devices connected over serial lines (such as RS-485 or RS-232).

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can communicate with a device. You must establish an active session using the appropriate connection function before executing any read or write transactions.

## Connection management

### `create`

Creates a Modbus client instance. The connection details follow in `connectTcp` or `connectRtu`.

#### Parameters

None.

#### Output

Returns the name of the created instance.

### `connectTcp`

Connects to a Modbus device over an Ethernet network.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>host</code></td><td>The hostname or IP address of the Modbus device.</td><td>string</td></tr><tr><td></td><td><code>port</code></td><td>The target network port. Default 1502, see <a href="#modbus-tcp-port-mapping">Modbus TCP port mapping</a>.</td><td>integer</td></tr><tr><td></td><td><code>unitId</code></td><td>The unit identifier of the target hardware. Default 1.</td><td>integer</td></tr><tr><td></td><td><code>socketTimeout</code></td><td>The connection timeout in milliseconds. Default 5000.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# options
host: 192.168.1.120
port: 502
unitId: 1
```

#### Output

Returns `true` when a network connection is successfully established. Throws an error if the connection fails.

### `disconnectTcp`

Closes the active Modbus TCP socket connection.

#### Parameters

None.

#### Output

Returns `true` when the network socket closes successfully, including when no connection exists.

### `connectRtu`

Connects to a Modbus device over a serial interface.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>path</code></td><td>The local platform file path of the serial port (such as <code>/dev/ttyUSB0</code> on Linux or <code>COM3</code> on Windows).</td><td>string</td></tr><tr><td></td><td><code>baudRate</code></td><td>The serial communication speed in bits per second. Default 9600.</td><td>integer</td></tr><tr><td></td><td><code>dataBits</code></td><td>The number of data bits per character frame (5, 6, 7, or 8). Default 8.</td><td>integer</td></tr><tr><td></td><td><code>stopBits</code></td><td>The number of stop bits at the end of each frame (1, 1.5, or 2). Default 1.</td><td>number</td></tr><tr><td></td><td><code>parity</code></td><td>The parity error-checking mode (none, even, or odd). Default 'none'.</td><td>string</td></tr><tr><td></td><td><code>unitId</code></td><td>The station address (unit ID) of the device on the serial bus. Default 1.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# options
path: /dev/ttyUSB0
baudRate: 19200
parity: even
unitId: 10
```

#### Output

Returns `true` when the serial port opens successfully. Throws an error if the connection fails.

### `disconnectRtu`

Closes the active Modbus RTU serial port connection.

#### Parameters

None.

#### Output

Returns `true` when the serial port closes successfully.

### `delete`

Removes the instance and frees its associated network or serial resources.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To communicate with the device again, you must trigger `create` anew.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Reading and writing

### `read`

Reads data from coils or registers on the connected Modbus device. The function automatically handles the underlying Modbus function code framing and parses raw buffers into primitives based on your configuration.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>fc</code></td><td>The Modbus function code used to request data (1: Read Coils, 2: Read Discrete Inputs, 3: Read Holding Registers, 4: Read Input Registers).</td><td>integer</td></tr><tr><td></td><td><code>address</code></td><td>The zero-based starting register or element offset address.</td><td>integer</td></tr><tr><td></td><td><code>length</code></td><td>The total number of sequential elements or 16-bit registers to read.</td><td>integer</td></tr><tr><td></td><td><code>dataType</code></td><td>The target binary parser type used to interpret the raw incoming buffer elements (raw, string, boolean, doubleBE, doubleLE, floatBE, floatLE, int16BE, int16LE, int32BE, int32LE, uint16BE, uint16LE, uint32BE, uint32LE). Unknown types fall back to raw with a logged warning. Default 'raw'.</td><td>string</td></tr></tbody></table>

#### Examples

Example 1: Read a single discrete coil element

```yaml
# options
fc: 1
address: 100
length: 1
dataType: boolean
```

Example 2: Read a 16-bit big-endian signed integer from a holding register

```yaml
# options
fc: 3
address: 40001
length: 1
dataType: int16BE
```

Example 3: Read a 32-bit big-endian floating point variable

Because 32-bit values span two discrete 16-bit Modbus memory registers, set the length parameter to 2.

```yaml
# options
fc: 4
address: 30010
length: 2
dataType: floatBE
```

#### Output

Returns the requested values fetched from the target hardware registers, parsed into the specified data type representation. Throws an error if the operation fails.

### `write`

Writes data payloads directly to target coil or register elements on the connected Modbus hardware.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>data</code></td><td></td><td>The single literal value, array of values, or raw binary Buffer payload to write to the destination device registers.</td><td>any</td></tr><tr><td><code>addressInfo</code></td><td><code>fc</code></td><td>The Modbus transaction function code (5: Write Single Coil, 6: Write Single Register, 15: Write Multiple Coils, 16: Write Multiple Registers).</td><td>integer</td></tr><tr><td></td><td><code>address</code></td><td>The zero-based starting offset address for the target elements.</td><td>integer</td></tr></tbody></table>

#### Examples

Example 1: Toggle a single coil active

```yaml
# data
true
# addressInfo
fc: 5
address: 100
```

Example 2: Set a single 16-bit register value

```yaml
# data
1234
# addressInfo
fc: 6
address: 40001
```

Example 3: Update multiple sequential register data elements

```yaml
# data
- 100
- 200
# addressInfo
fc: 16
address: 40050
```

#### Output

Returns the raw response object of the underlying jsmodbus client, containing the request, the device response, and timing metrics. The relevant information for flows is that the call completed without throwing. Throws an error if the write fails.

## String helper functions

### `readString`

Reads register values sequentially from a specified holding register starting address and extracts them as a decoded text string.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>startAddress</code></td><td>The zero-based register starting offset address.</td><td>integer</td></tr><tr><td><code>length</code></td><td>The total number of consecutive 16-bit registers containing the string character sequence.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# startAddress
40100
# length
10
```

#### Output

Returns the text string parsed from the targeted registers, with all null padding characters removed. Throws an error if the read fails or no data is received.

### `writeString`

Encodes a text string and writes it across consecutive holding registers. See [Text string encoding padding](#text-string-encoding-padding) for how uneven byte lengths are handled.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>text</code></td><td>The text string to transmit to the target device.</td><td>string</td></tr><tr><td><code>startAddress</code></td><td>The zero-based register destination starting offset address.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# text
New Product ID
# startAddress
40100
```

#### Output

Returns the raw response object of the underlying jsmodbus client, like `write`. Throws an error if the operation fails or `text` is not a string.

## Tips and tricks

### Modbus TCP port mapping

While the official Modbus TCP standard mandates network communication over port 502, several virtual test rigs or secure industrial gateway firewalls route traffic along port 1502. The connector automatically binds to port 1502 by default. If your physical controller expects standard port constraints, explicitly override the port assignment inside your configuration options block during connection initialization.

### Text string encoding padding

Modbus memory maps allocate a full 16-bit word space per register, whereas conventional text strings occupy single 8-bit bytes per character. When executing `writeString`, the string processor handles this allocation automatically. If your text payload compiles to an uneven byte length count, the helper joins a trailing null termination byte (`0x00`) to fill the final register block correctly.


# MQTT Client

The MQTT client connector manages client connections to an MQTT broker over various transport protocols, including standard TCP, TLS, and WebSockets. It automatically handles server keep-alive pings, Quality of Service (QoS) delivery flows, automatic reconnection, and message queuing before the connection is established.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can communicate with an external broker, though it includes a pre-initialized internal option.

Heisenware provides a built-in, pre-configured instance named `internal-mqtt` connected directly to the platform's local broker. You can use `internal-mqtt` directly in your application logic to publish or subscribe to internal topics without defining connection configurations. To communicate with a distinct, external third-party broker, create a separate instance and use the [connection management](#connection-management) functions below.

<p align="center"><br><img src="/files/h7mzcm3aeE6fIzaeg67t" alt=""></p>

## Two ways to use MQTT

Which setup you need depends on where the broker runs:

* **Your devices or software act as MQTT clients** and should exchange data with Heisenware. You need no broker of your own and no connector instance. Your clients connect to your account's Heisenware broker, and inside the App Builder the built-in `internal-mqtt` instance handles the messages. See [Connecting an external client to Heisenware](#connecting-an-external-client-to-heisenware).
* **You run your own MQTT broker** (or use a third-party broker such as HiveMQ). Create a connector instance with [`create`](#create) and connect it to that broker with `connect`.

## Connecting an external client to Heisenware

External devices and scripts connect as MQTT clients of your account's broker. Data published this way arrives on the internal broker, where `internal-mqtt` can subscribe to it, and messages published through `internal-mqtt` reach the external client in turn.

To connect an external client, first generate credentials in the [Integrations panel](/app-manager/inbound-integrations) of the App Manager, then configure your client with these credentials and the following connection details:

* Hostname: `<account>.heisenware.cloud`
* Port: `8884` (MQTTS, TLS encrypted)
* Protocol version: MQTT 3.1.1 (the broker can refuse MQTT 5 connections)
* Topic prefix: Your domain, the combination of account and workspace. For example, an account named `my-company` publishes to a topic like `my-company.default/test`.

{% hint style="info" %}

#### Server certificate

Standard CA certificates work, for example the system certificate store under `/etc/ssl/certs/`. If your environment does not trust the Heisenware certificate, enable your client's option to proceed without validating the server certificate.
{% endhint %}

For a complete walkthrough, including how to process the incoming data in an App, see [Connect an external MQTT client](/tutorials/integration-guides/connect-an-external-mqtt-client).

## Connection management

### `create`

Creates a new, named connector instance for communicating with an external broker.

After creating an instance, use `connect` to establish the broker connection.

#### Parameters

None.

#### Output

Returns the name of the created instance.

### `connect`

Establishes a connection to the specified MQTT broker. If the client is already connected to the same URL with the same options, the function does nothing. If you target a different broker or change options, the client disconnects from the current broker before establishing the new connection.

#### Parameters

<table><thead><tr><th width="95.28619384765625">Input</th><th width="167.6767578125">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The broker URL including the transport protocol prefix (such as <code>mqtt://broker.hivemq.com</code> or <code>mqtts://test.mosquitto.org</code>). Supported protocols: <code>mqtt</code>, <code>mqtts</code>, <code>tcp</code>, <code>tls</code>, <code>ws</code>, <code>wss</code>.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>clientId</code></td><td>A unique identifier for the client session. Generates a random identifier if omitted.</td><td>string</td></tr><tr><td></td><td><code>username</code></td><td>The username required by the broker, if any.</td><td>string</td></tr><tr><td></td><td><code>password</code></td><td>The password required by the broker, if any.</td><td>string</td></tr><tr><td></td><td><code>keepalive</code></td><td>The interval in seconds between keep-alive pings. Set to 0 to disable. Default 60.</td><td>integer</td></tr><tr><td></td><td><code>connectTimeout</code></td><td>The time in milliseconds to wait for the connection acknowledgment before the connection fails. Default 30000.</td><td>integer</td></tr><tr><td></td><td><code>reconnectPeriod</code></td><td>The interval in milliseconds between two reconnection attempts. Set to 0 to disable automatic reconnection. Default 1000.</td><td>integer</td></tr><tr><td></td><td><code>clean</code></td><td>Set to false to receive QoS 1 and 2 messages while offline. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>resubscribe</code></td><td>When the connection breaks and reconnects, subscribed topics are subscribed again automatically. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>queueQoSZero</code></td><td>Queue outgoing QoS 0 messages while the connection is broken. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>will</code></td><td>A last will and testament configuration object the broker delivers if the client disconnects ungracefully. Keys: <code>topic</code>, <code>payload</code>, <code>qos</code>, <code>retain</code>.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# url
mqtt://broker.hivemq.com
# options
username: my-device-user
password: my-secret-password
will:
  topic: devices/my-device/status
  payload: offline
  qos: 1
  retain: true
```

#### Output

Returns `true` when the connection is established. Throws an error if the connection fails.

### `disconnect`

Closes the connection to the MQTT broker and removes all message listeners of the instance.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>force</code></td><td>When set to true, the client closes the connection immediately without waiting for in-flight messages to be acknowledged. Default false.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns `true` upon successful disconnection, including when no connection exists.

### `isConnected`

Checks whether the client has an active connection to the broker.

#### Parameters

None.

#### Output

Returns `true` if connected, or `false` if disconnected.

### `isReconnecting`

Checks whether the client is currently trying to reconnect after a connection failure.

#### Parameters

None.

#### Output

Returns `true` if a reconnection attempt is running, or `false` if it is not.

### `delete`

Removes the instance configuration.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To communicate with the broker again, you must trigger `create` anew.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Publishing messages

### `publishString`

Publishes a text string payload to a specific topic. Publishing works even before the connection is established, see [Pre-handshake publication queuing](#pre-handshake-publication-queuing).

#### Parameters

<table><thead><tr><th width="102.02020263671875">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>topic</code></td><td></td><td>The topic to publish to.</td><td>string</td></tr><tr><td><code>message</code></td><td></td><td>The text message payload to publish.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>qos</code></td><td>The Quality of Service (QoS) delivery guarantee level (0, 1, or 2). Default 0.</td><td>integer</td></tr><tr><td></td><td><code>retain</code></td><td>When set to true, the broker stores the message as the last known value for the topic. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>dup</code></td><td>Marks the message as a duplicate. Default false.</td><td>boolean</td></tr></tbody></table>

#### Example

```yaml
# topic
devices/my-device/log
# message
Device starting up...
# options
qos: 1
```

#### Output

Returns nothing for a QoS 0 publication and the broker acknowledgment packet for QoS 1 and 2. Throws an error if publication fails.

### `publishJson`

Publishes a structured data object to a specific topic. The connector serializes the payload into a JSON string before transmission.

#### Parameters

<table><thead><tr><th width="112.12127685546875">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>topic</code></td><td></td><td>The topic to publish to.</td><td>string</td></tr><tr><td><code>message</code></td><td></td><td>The structured data object payload to publish.</td><td>object</td></tr><tr><td><code>options</code></td><td><code>qos</code></td><td>The Quality of Service (QoS) delivery guarantee level (0, 1, or 2). Default 0.</td><td>integer</td></tr><tr><td></td><td><code>retain</code></td><td>When set to true, the broker stores the message as the last known value for the topic. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>dup</code></td><td>Marks the message as a duplicate. Default false.</td><td>boolean</td></tr></tbody></table>

#### Example

```yaml
# topic
devices/my-device/data
# message
temperature: 21.5
humidity: 45.2
```

#### Output

Returns nothing for a QoS 0 publication and the broker acknowledgment packet for QoS 1 and 2. Throws an error if publication fails.

## Subscribing to messages

### `subscribe`

Subscribes to one or more topics so the client receives their message streams. See [Topic wildcards](#topic-wildcards) for matching multiple topics.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>topic</code></td><td></td><td>A topic string or an array of topic strings. Supports topic wildcards (<code>+</code> for a single level and <code>#</code> for multiple levels).</td><td>string or array</td></tr><tr><td><code>options</code></td><td><code>qos</code></td><td>The maximum requested Quality of Service (QoS) level. Default 0.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# topic
sensors/+/temperature
# options
qos: 1
```

#### Output

Returns `true` when the subscription is registered.

### `onStringMessage`

Attaches an event listener that receives incoming messages as raw text strings.

#### Parameters

<table><thead><tr><th width="129.7979736328125">Input</th><th width="92.22216796875">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>listener</code></td><td></td><td>The callback triggered on message arrival. Receives the payload string, the source topic, and the raw packet metadata.</td><td>callback</td></tr><tr><td><code>topic</code></td><td></td><td>An optional topic string or array of topics. Adds these topics to the subscription and only delivers matching messages. If omitted, the callback receives messages from all active subscriptions on the instance.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>qos</code></td><td>The QoS subscription level. Default 0.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# listener
<callback>
# topic
devices/my-device/commands
```

#### Output

Returns the string `subscribed` to confirm listener registration.

### `onJsonMessage`

Attaches an event listener that parses incoming messages into JSON objects. If a payload fails to parse, the connector skips the message and logs a warning.

#### Parameters

<table><thead><tr><th width="115.48809814453125">Input</th><th width="80.4376220703125">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>listener</code></td><td></td><td>The callback executed on valid message arrival. Receives the parsed data object enhanced with a <code>__topic__</code> attribute containing the source topic, plus the source topic and the raw packet metadata as separate arguments.</td><td>callback</td></tr><tr><td><code>topic</code></td><td></td><td>An optional topic string or array of topics. Adds these topics to the subscription and only delivers matching messages. If omitted, the callback receives messages from all active subscriptions on the instance.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>qos</code></td><td>The QoS subscription level. Default 0.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# listener
<callback>
# topic
devices/my-device/config
```

#### Output

Returns the string `subscribed` to confirm listener registration.

### `unsubscribe`

Unsubscribes from one or more topics and stops delivering their messages.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>topic</code></td><td>A topic string or an array of topic strings to remove.</td><td>any</td></tr></tbody></table>

#### Output

Returns the broker acknowledgment. Throws an error if the operation fails.

## Utility functions

### `getLastMessageId`

Gets the packet identifier of the most recently sent outbound message.

#### Parameters

None.

#### Output

Returns an integer matching the identifier of the last sent packet.

## Tips and tricks

### Connecting a Mosquitto bridge

When bridging a local Mosquitto broker to Heisenware, add these options to the bridge configuration:

* `notifications false`. Bridges try to publish their status to `$SYS` system topics by default. The Heisenware broker does not allow writing to `$SYS` topics and disconnects the client.
* `try_private false`. The bridge then behaves like a regular client. The broker does not support the private bridge mode.

### Topic wildcards

MQTT topic levels use forward slashes (`/`) as separators. When binding message listeners, use `+` to match any value at a single level, or a trailing `#` to capture all nested levels below that branch.

### Pre-handshake publication queuing

You can call `publishString` or `publishJson` before the client finishes its initial connection handshake. Messages sent during startup or a temporary connection loss queue in memory and transmit automatically once the connection resolves.

## Video demo

The video shows how to create an MQTT client instance and connect it to an external, third-party broker such as HiveMQ.

{% embed url="<https://www.youtube.com/watch?v=QG1Wsac2NbU>" %}


# OPC UA Client

Learn how to connect to an OPC UA server using the Heisenware OPC UA client.

The OPC UA client connector (`OpcuaClient`) communicates with OPC UA servers. It manages secure connections, browses the server's address space, reads and writes variables, calls methods, monitors data for changes, and transfers files.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can manage the connection and session with a server. For secure connections, generate certificates using `createCertificates`.

{% hint style="info" %}
See the [Video demo](#video-demo) at the bottom of this page.
{% endhint %}

## Security and certificates

{% hint style="info" %}
For unencrypted connections, skip directly to [Connection and lifecycle](#connection-and-lifecycle).
{% endhint %}

Secure OPC UA communication (`Sign` or `SignAndEncrypt`) requires a Public Key Infrastructure (PKI) to manage digital certificates and establish trust between the client and the server. Only create a PKI store when connecting with a `securityMode` of `Sign` or `SignAndEncrypt`. For unsecured connections, you can ignore certificate management.

### Self-signed and CA-signed certificates

`createCertificates` prepares the client for secure connections in one of two modes:

* **Self-signed (default)**: The client creates its own certificate without a signature from a certificate authority. This is the simplest approach and works best for most scenarios.
* **CA-signed (set `useCA` to `true`)**: The client creates its own Certificate Authority (CA) to sign the application and user certificates. Use this if the server trusts a single CA instead of multiple individual client certificates.

### Establishing trust

OPC UA security requires a two-way trust model:

* **The server trusts the client**: Configure the server to accept the client's public certificate.
* **The client trusts the server**: Add the server's public certificate to the client's trust list to prevent man-in-the-middle attacks.

Manage this process using `createCertificates` and `addServerCertificate`.

### Client PKI folder structure

`createCertificates` generates a standard `pki` folder structure:

* `pki/own/certs/`: The client's public certificates (for example, `heisenware_opcua_client.pem`). Provide this file to the server administrator.
* `pki/own/private/`: The client's private keys. Keep these keys secret. The client automatically restricts access permissions.
* `pki/trusted/certs/`: The client's trust list. Place the public certificates of trusted OPC UA servers in this folder. Use `addServerCertificate` to automate this.
* `pki/issuers/certs/`: In CA mode, this folder holds the public certificate of the CA that issues certificates. If an external CA signed the server certificate, add the server's public CA certificate here using `addCertificateAuthority`.

{% hint style="info" %}

#### PKI store location

The location of the `pki` folder depends on where the client runs:

* **Agent**: The folder resides in the same directory as your Agent executable.
* **Platform**: The folder resides under `/shared/certificates`. Click the refresh icon in the File Explorer to view it.
  {% endhint %}

## Certificate management

These static functions manage secure connection setup.

### `createCertificates`

Initializes the local PKI store and creates a client certificate for the application and a user certificate for authentication. By default, this function creates self-signed certificates. Run this function once. Existing certificates are kept on repeated runs.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>useCA</code></td><td>Creates a local Certificate Authority to sign the certificates. Default false.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns `true` when the PKI structure and certificates are successfully created.

### `addServerCertificate`

Adds a server's public certificate to the client's trust list to establish a secure connection.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>certificateInput</code></td><td>The server's public certificate, specified as a file path or PEM string.</td><td>string</td></tr><tr><td><code>certificateName</code></td><td>An optional filename for the certificate. Required if providing a PEM string.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true` when the certificate is saved successfully. Throws an error if the input is missing, the filename is missing for a PEM string, or saving fails.

#### Examples

**Example 1: Add a certificate from a file**

{% hint style="info" %}
If the client runs on the platform (not in Agent mode), upload the server certificate using the File Explorer, drag the file to this parameter, and then delete it from the uploads folder.
{% endhint %}

```yaml
# certificateInput
/path/to/downloaded/server_cert.pem
```

**Example 2: Add a certificate from a string**

```yaml
# certificateInput
'-----BEGIN CERTIFICATE-----\nMIIC...etc...\n-----END CERTIFICATE-----'
# certificateName
my_trusted_server.pem
```

### `addCertificateAuthority`

Adds a server's public CA certificate to the `issuers` directory of the PKI store. Use this if a Certificate Authority signed the server certificate.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>certificateInput</code></td><td>The CA's public certificate, specified as a file path or PEM string.</td><td>string</td></tr><tr><td><code>certificateName</code></td><td>An optional filename for the CA certificate. Required if providing a PEM string.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true` when the certificate is saved successfully. Throws an error if the input is missing, the filename is missing for a PEM string, or saving fails.

## Connection and lifecycle

### `create`

Creates an OPC UA client instance. The security settings determine how the client connects.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>securityMode</code></td><td>The security mode to use (<code>None</code>, <code>Sign</code>, or <code>SignAndEncrypt</code>). Default <code>None</code>.</td><td>string</td></tr><tr><td></td><td><code>securityPolicy</code></td><td>The encryption algorithm to use (such as <code>Basic256Sha256</code>). Default <code>None</code>.</td><td>string</td></tr><tr><td></td><td><code>automaticallyAcceptUnknownCertificate</code></td><td>Disables server validation. Default false.</td><td>boolean</td></tr></tbody></table>

{% hint style="danger" %}

#### Security risk

Never set `automaticallyAcceptUnknownCertificate` to `true` in production. This disables server validation and exposes the system to man-in-the-middle attacks. Use it for debugging purposes only.
{% endhint %}

#### Output

Returns the name of the created instance.

#### Examples

**Example 1: Create a client for an unsecured connection**

```yaml
# (No arguments needed)
```

**Example 2: Create a client for a secure connection**

```yaml
# options
securityMode: SignAndEncrypt
securityPolicy: Basic256Sha256
```

### `connect`

Connects to an OPC UA server. If a secure connection fails, see [Tips and tricks](#tips-and-tricks) for troubleshooting the chain of trust.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>endpointUrl</code></td><td></td><td>The full URL of the server endpoint (such as <code>opc.tcp://my-server.com:4840</code>).</td><td>string</td></tr><tr><td><code>userIdentity</code></td><td><code>username</code></td><td>The username for authentication.</td><td>string</td></tr><tr><td></td><td><code>password</code></td><td>The password for authentication.</td><td>string</td></tr><tr><td></td><td><code>userCertificate</code></td><td>The user certificate for certificate-based authentication.</td><td>string</td></tr><tr><td></td><td><code>userPrivateKey</code></td><td>The private key belonging to the user certificate.</td><td>string</td></tr><tr><td></td><td><code>useDefaultUserCertificate</code></td><td>Set to <code>true</code> to authenticate with the user certificate created by <code>createCertificates</code>. Default false.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns `true` when the connection succeeds or the client is already connected. Returns the string `reconnect ongoing` if an automatic reconnection is in progress. Throws an error on failure.

#### Examples

Each scenario shows the inputs of both `create` and `connect`.

**Example 1: Unsecured, anonymous connection**

Requires no PKI setup and no user identity.

```yaml
# (In create)
# (No arguments)

# (In connect)
# endpointUrl
opc.tcp://my-server.com:4840
```

**Example 2: Secure, anonymous connection**

Requires the PKI setup (`createCertificates` and `addServerCertificate`) but no user identity.

```yaml
# (In create)
# options
securityMode: SignAndEncrypt
securityPolicy: Basic256Sha256

# (In connect)
# endpointUrl
opc.tcp://my-secure-server.com:4840
```

**Example 3: Secure connection with username and password**

Requires the PKI setup for a secure channel, plus credentials for user authentication.

```yaml
# (In create)
# options
securityMode: SignAndEncrypt
securityPolicy: Basic256Sha256

# (In connect)
# endpointUrl
opc.tcp://my-secure-server.com:4840
# userIdentity
username: myuser
password: mysecretpassword
```

**Example 4: Secure connection with a user certificate**

The most secure method, using certificates for both channel security and user authentication.

```yaml
# (In create)
# options
securityMode: SignAndEncrypt
securityPolicy: Basic256Sha256

# (In connect)
# endpointUrl
opc.tcp://my-secure-server.com:4840
# userIdentity
useDefaultUserCertificate: true
```

### `disconnect`

Disconnects from the OPC UA server and closes the active session.

#### Parameters

None.

#### Output

Returns `true` on successful disconnection, including when no connection exists.

### `isConnected`

Checks whether the client is connected to the server.

#### Parameters

None.

#### Output

Returns `true` if connected, or `false` if disconnected.

### `delete`

Removes the client instance and closes the connection.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To communicate with the server again, you must create a new instance.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Browsing

### `browse`

Browses a node address on the server.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>address</code></td><td>The <code>nodeId</code> or browse path (such as <code>/0:Objects/2:Demo</code>) where browsing starts.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of objects representing each node found, including its name, ID, and class.

#### Example

```yaml
# address
/0:Objects/2:Demo
```

### `browseObjects`

Browses the server's Objects folder.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>path</code></td><td>An optional browse path starting inside the Objects folder, or a <code>nodeId</code>. Browses the Objects folder itself if omitted.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of objects representing each node found.

#### Example

```yaml
# path
2:Demo/2:Dynamic/2:Scalar
```

### `browseTypes`

Browses the server's Types folder to explore the data type hierarchy.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>path</code></td><td>An optional browse path starting inside the Types folder.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of objects representing each node found.

#### Example

```yaml
# path
0:BaseObjectType/0:FolderType
```

### `browseViews`

Browses the server's Views folder.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>path</code></td><td>An optional browse path starting inside the Views folder.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of objects representing each node found.

#### Example

```yaml
# path
0:Server
```

## Reading and writing

### `readNode`

Reads all attributes of an OPC UA node.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>address</code></td><td>The <code>nodeId</code> or browse path of the node to read.</td><td>string</td></tr></tbody></table>

#### Output

Returns a JSON object containing the node's attributes, status code, and timestamps.

```json
{
  "value": {
    "dataType": "Int32",
    "value": 12345
  },
  "statusCode": {
    "name": "Good",
    "value": 0
  },
  "serverTimestamp": "2025-07-11T08:52:34.000Z",
  "sourceTimestamp": "2025-07-11T08:52:34.000Z"
}
```

#### Examples

**Example 1: Read using a nodeId**

```yaml
# address
ns=2;s=Demo.Dynamic.Int32
```

**Example 2: Read using a browse path**

```yaml
# address
/0:Objects/2:Demo/2:Dynamic/2:Int32
```

### `readVariable`

Reads the value of a single variable from the server.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>address</code></td><td>The <code>nodeId</code> or browse path of the variable to read.</td><td>string</td></tr></tbody></table>

#### Output

Returns the raw value of the variable.

#### Examples

**Example 1: Read using a nodeId**

```yaml
# address
ns=2;s=Demo.Dynamic.Int32
```

**Example 2: Read using a browse path**

```yaml
# address
/0:Objects/2:Demo/2:Dynamic/2:Int32
```

### `writeVariable`

Writes a new value to a server variable. Converts the value to the required OPC UA data type before writing. If the variable is read-only, this function throws an error.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>address</code></td><td></td><td>The <code>nodeId</code> or browse path of the variable.</td><td>string</td></tr><tr><td><code>value</code></td><td></td><td>The new value to set.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>skipTypeChecking</code></td><td>If <code>true</code>, the client skips reading metadata and permissions before writing. Default false.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns nothing on a successful write. Throws an error on failure.

#### Example

```yaml
# address
ns=2;s=Demo.Dynamic.Int32
# value
42
```

### `callMethod`

Invokes a method on an OPC UA object.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>methodAddress</code></td><td>The <code>nodeId</code> or browse path of the method to call.</td><td>string</td></tr><tr><td><code>inputValues</code></td><td>An array of input arguments. Default [].</td><td>array</td></tr></tbody></table>

#### Output

Returns an array containing the output arguments from the method call. Throws an error if the number of input values does not match the method definition or the call fails.

#### Example

```yaml
# methodAddress
ns=2;s=Demo.Methods.Multiply
# inputValues
  - 5
  - 10
```

## Monitoring

### `monitorNode`

Subscribes to changes of an OPC UA node. Triggers the callback on every change.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>address</code></td><td></td><td>The <code>nodeId</code> or browse path of the node.</td><td>string</td></tr><tr><td><code>listener</code></td><td></td><td>Callback evaluated on every change. Receives a JSON object containing the variable's <code>dataType</code> and <code>value</code>.</td><td>callback</td></tr><tr><td><code>options</code></td><td><code>samplingInterval</code></td><td>How often the server checks for changes, in milliseconds. Default 1000.</td><td>integer</td></tr><tr><td></td><td><code>queueSize</code></td><td>Maximum number of queued notifications on the server. Default 100.</td><td>integer</td></tr><tr><td></td><td><code>discardOldest</code></td><td>If <code>true</code>, drops the oldest notification when the queue is full. Default true.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns the resolved `nodeId` of the monitored item. Use this ID with `stopMonitor` to terminate monitoring.

#### Example

```yaml
# address
ns=2;s=Demo.Dynamic.UInt16
# listener
<callback>
# options
samplingInterval: 5000
```

### `monitorVariable`

Subscribes to value changes of a variable. Triggers the callback with the new value on every change.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>address</code></td><td></td><td>The <code>nodeId</code> or browse path of the variable.</td><td>string</td></tr><tr><td><code>listener</code></td><td></td><td>Callback evaluated on every change. Receives the raw value of the variable.</td><td>callback</td></tr><tr><td><code>options</code></td><td><code>samplingInterval</code></td><td>How often the server checks for changes, in milliseconds. Default 1000.</td><td>integer</td></tr><tr><td></td><td><code>queueSize</code></td><td>Maximum number of queued notifications on the server. Default 100.</td><td>integer</td></tr><tr><td></td><td><code>discardOldest</code></td><td>If <code>true</code>, drops the oldest notification when the queue is full. Default true.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns the resolved `nodeId` of the monitored item. Use this ID with `stopMonitor` to terminate monitoring.

#### Example

```yaml
# address
ns=2;s=Demo.Dynamic.UInt16
# listener
<callback>
# options
samplingInterval: 5000
```

### `stopMonitor`

Stops an active subscription for a monitored item.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>nodeId</code></td><td>The <code>nodeId</code> returned by <code>monitorNode</code> or <code>monitorVariable</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true` when the subscription terminates successfully. Throws an error on failure.

#### Example

```yaml
# nodeId
ns=2;s=Demo.Dynamic.UInt16
```

## File transfer

### `browseDirectory`

Recursively browses a directory structure on the server.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>address</code></td><td>The <code>nodeId</code> or browse path of the directory node.</td><td>string</td></tr></tbody></table>

#### Output

Returns a nested array of objects representing the directory structure.

### `readFile`

Reads the contents of a file on the server.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>address</code></td><td></td><td>The <code>nodeId</code> or browse path of the file.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>encoding</code></td><td>The encoding of the returned content (such as <code>ascii</code> or <code>utf8</code>). Default <code>base64</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns the file content as a string in the requested encoding.

#### Example

```yaml
# address
ns=2;s=Demo.Files.TextFile
```

### `writeFile`

Creates a file on the server and uploads content to it.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>folderAddress</code></td><td>The <code>nodeId</code> or browse path of the target folder.</td><td>string</td></tr><tr><td><code>newFileName</code></td><td>The name of the new file.</td><td>string</td></tr><tr><td><code>pathOrBase64</code></td><td>The file content, specified as a base64 string or local file path.</td><td>string</td></tr></tbody></table>

#### Output

Returns the `nodeId` of the newly created file on the server.

#### Example

```yaml
# folderAddress
ns=2;s=Demo.Files
# newFileName
report.txt
# pathOrBase64
SGVsbG8sIFdvcmxkIQ==
```

### `deleteFile`

Deletes a file on the server.

{% hint style="danger" %}

#### Irreversible action

Deleting a file permanently removes it from the server. This action cannot be undone.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>folderAddress</code></td><td>The <code>nodeId</code> or browse path of the folder containing the file.</td><td>string</td></tr><tr><td><code>fileName</code></td><td>The name of the file to delete.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true` when the file is successfully deleted, or `false` if the deletion fails or the folder provides no delete capability. Throws an error if the file cannot be found.

#### Example

```yaml
# folderAddress
ns=2;s=Demo.Files
# fileName
report.txt
```

## Event listeners

### `listenToEvents`

Registers a callback to receive client lifecycle events.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>listener</code></td><td>Callback evaluated on client lifecycle events. Receives one of the following event strings: <code>Connected</code>, <code>Connection Failed</code>, <code>Connection Lost</code>, <code>Started Reconnection</code>, <code>Connection Re-Established</code>, <code>Back Off</code>, <code>Security Token Renewed</code>, <code>Request Timed Out</code>, <code>Session Closed</code>, <code>Subscription Started</code>, <code>Subscription Keep Alive</code>, <code>Subscription Terminated</code>.</td><td>callback</td></tr></tbody></table>

#### Output

Returns `true` on successful registration.

## Deprecated functions

The following functions are maintained for backward compatibility. Update your App logic to use the recommended replacements.

| Deprecated function  | Use instead     |
| -------------------- | --------------- |
| `readVariableValue`  | `readVariable`  |
| `writeVariableValue` | `writeVariable` |

## Tips and tricks

Establishing a secure certificate-based connection is the primary point of failure in OPC UA. An error usually indicates a broken link in the chain of trust. Use these troubleshooting steps to resolve common issues.

### Switch an existing instance to a secure connection

To switch an unsecured instance to a secure connection, remove the instance and create it again. Right-click the existing active instance (green in the UI), click **Remove**, and the instance turns yellow to indicate it is not available. Trigger the `create` function again to apply your new security configuration.

### Server rejects the client certificate

If the client attempts to connect and the server immediately closes the connection (often showing an error such as `The connection has been disconnected by third party`), the server does not trust the client's application certificate.

To resolve this (using Prosys Simulation Server as an example):

1. Attempt to connect the client to the Prosys server. This fails but registers the client's certificate with the server.
2. Open the **Certificates** tab in the Prosys Simulation Server UI.
3. Locate the client certificate (`HeisenwareOPCUAClient`) in the **Rejected Certificates** list.
4. Right-click the certificate and select **Trust** to move it to the **Trusted Certificates** list.
5. Connect again.

In CA mode, add the CA's public certificate (`heisenware_ca_cert.pem`) to the server's PKI issuers directory (`pki/CA/issuers/certs/`) instead of trusting individual certificates.

### Client rejects the server certificate

If the client does not trust the server, it fails with the error `server Certificate verification failed`.

To resolve this, add the server's public certificate to the client's trust store:

1. Export the server's public certificate file (such as exporting from the Prosys **Certificates** tab).
2. Use `addServerCertificate` to save the file to the client's `pki/trusted/certs` folder.

### SAN mismatch

Even with established trust, the client rejects the connection if the hostname in the endpoint URL does not match any address in the server certificate's Subject Alternative Name (SAN) field.

To resolve this (using Prosys as an example):

1. If connecting to `opc.tcp://localhost:53530` fails, inspect the certificate. If the SAN field only lists `DNS:lenovo`, you must match that hostname.
2. Update the endpoint URL to use the correct hostname, such as `opc.tcp://lenovo:53530/OPCUA/SimulationServer`.

### Certificate revocation list failures

If a server certificate points to a Certificate Revocation List (CRL), the client attempts to download this list to verify validity. In isolated networks without internet access, this lookup fails and blocks the connection.

To resolve this, download the CRL file manually and place it in the client's `pki/issuers/crl` or `pki/trusted/crl` folder. If you generated the server certificate with a custom CA, you can create an empty CRL file to satisfy this check.

### Application and user authentication

These two certificate types serve distinct purposes:

1. **Application certificate (`heisenware_opcua_client.pem`)**: Identifies the application to establish the secure, encrypted channel between client and server. This is mandatory for secure connections.
2. **User certificate (`heisenware_opcua_user.pem`)**: Identifies the user to handle authentication and permissions after the secure channel is established. This is optional.

User certificate authentication requires server-side configuration. The server administrator must create the user account and map it explicitly to the user's public certificate. For Prosys Simulation Server, this feature is only available in the Professional Edition.

### Server and client clocks out of sync

OPC UA blocks secure connections if the clocks of the client and server differ substantially (for example, by an hour). When this occurs, the client logs a warning.

## Video demo

Watch the video to learn how to connect to an OPC UA server, read, record, and visualize data.

{% embed url="<https://www.youtube.com/watch?t=15s&v=7TNHk2eqRWc>" %}


# OPC UA Server

OPC UA server starts and runs a custom OPC UA server on your infrastructure. Use it to construct a declarative information model out of folders, objects, and variables, and attach logic to process data reads and writes from external OPC UA clients.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can configure network ports, map variable schemas, and manage the server lifecycle.

## Variable interaction types

Variables are defined inside objects within the server's information model. Their operational behavior is governed by three distinct configuration categories:

* **Getters (read-only for clients)** – Managed internally by your logic. External OPC UA clients can read these values but cannot modify them. Update a getter variable by calling `setValue` whenever its real-world state changes.
* **Setters (write-only for clients)** – Designed to ingest data updates transmitted from external OPC UA clients. When a client modifies a setter node, the server triggers the `onSet` event handler. After your logic processes the data, you must invoke `setValue` to finalize the node synchronization.
* **Requestors (read-on-demand for clients)** – Variables whose data payloads are not held in continuous server cache memory. When a client reads a requestor node, the server fires the `onRequest` event handler. Your logic must then immediately calculate or fetch the data value and provide it to the server using `setValue`.

## Server lifecycle

### `create`

Creates an unconnected OPC UA server instance and maps out its information model structure.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>objects</code></td><td>An array defining folders, objects, and variables inside the server information model. Each node requires a <code>path</code> and a <code>type</code> (<code>folder</code> or <code>object</code>), along with <code>getters</code>, <code>setters</code>, or <code>requestors</code> type maps. An object can optionally define an integer <code>offset</code> to assign fixed numeric nodeIds to the object and its getter variables.</td><td>array</td></tr><tr><td></td><td><code>port</code></td><td>The TCP port where the server listens for inbound connections. Separate parallel server instances must use distinct port numbers. Default 4840.</td><td>integer</td></tr><tr><td></td><td><code>allowAnonymous</code></td><td>Controls whether external clients can connect without credentials. When false, clients must authenticate with the credentials of an integration user. Default true. See <a href="#protocol-and-encryption">Protocol and encryption</a> for the supported security level.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns the name of the created instance.

#### Example

```yaml
# options
port: 4841
allowAnonymous: true
objects:
  - path: Machine1
    type: folder
  - path: Machine1/Status
    type: object
    getters:
      currentSpeed: integer
      isHot: boolean
    setters:
      targetSpeed: integer
    requestors:
      uptime: string
```

### `start`

Initializes and starts the underlying OPC UA server engine, exposing the endpoint to network traffic.

#### Parameters

None.

#### Output

Returns a string containing the primary endpoint connection URL (for example, `opc.tcp://localhost:4841/UA/HeisenwareOPCUAServer`), including when the server is already running. Throws an error if starting fails.

### `stop`

Shuts down the active server engine and releases occupied network sockets.

#### Parameters

None.

#### Output

Returns nothing on a successful shutdown. Throws an error if stopping fails.

### `isStarted`

Queries whether the underlying server engine is running and accepting client connections.

#### Parameters

None.

#### Output

Returns `true` if the server engine is active, or `false` if it is not.

### `delete`

Removes the instance and its configuration.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To run the server again, you must create a new instance.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Data operations and events

### `setValue`

Sets a new data value for a specific variable node on the server. This function updates getter nodes and serves as the response within your custom `onSet` and `onRequest` event scripts. The value must match the declared type, see [Data type validation](#data-type-validation).

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>variablePath</code></td><td>The destination path targeting a specific node variable, formatted as <code>path/to/object:variableName</code>.</td><td>string</td></tr><tr><td><code>value</code></td><td>The data payload to store inside the node variable. Must match the declared schema data type.</td><td>any</td></tr></tbody></table>

#### Output

Returns `true` if the node variable updates successfully, or `false` if the path, variable, or data type is invalid (the reason logs as a warning).

#### Example

```yaml
# variablePath
Machine1/Status:currentSpeed
# value
1500
```

### `onSet`

Registers an event callback executed whenever an external OPC UA client writes a new value to a designated setter variable node.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>variablePath</code></td><td>The path of the setter variable node to monitor, formatted as <code>path/to/object:variableName</code>.</td><td>string</td></tr><tr><td><code>listener</code></td><td>The callback evaluated when a write occurs. Receives the updated value sent by the client.</td><td>callback</td></tr></tbody></table>

#### Output

Returns `'subscribed'` when successfully registered.

#### Example

```yaml
# variablePath
Machine1/Status:targetSpeed
# listener
<callback>
```

### `onRequest`

Registers an event callback executed whenever an external OPC UA client attempts to read a designated requestor variable node on-demand.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>variablePath</code></td><td>The path of the requestor variable node to monitor, formatted as <code>path/to/object:variableName</code>.</td><td>string</td></tr><tr><td><code>listener</code></td><td>The callback evaluated when an on-demand read request arrives.</td><td>callback</td></tr></tbody></table>

#### Output

Returns `'subscribed'` when successfully registered.

#### Example

```yaml
# variablePath
Machine1/Status:uptime
# listener
<callback>
```

### `onServerUpdate`

Registers a global diagnostic event callback executed whenever any variable node value updates on the server via `setValue`. Notifications are throttled, see [Server update throttling](#server-update-throttling).

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>listener</code></td><td>The callback executed on a value update. Receives an epoch millisecond timestamp and the modified variable path string.</td><td>callback</td></tr></tbody></table>

#### Output

Returns `'subscribed'` when successfully registered.

#### Example

```yaml
# listener
<callback>
```

## Complete usage example

The steps show how to configure and run the server based on the model defined in the `create` example.

{% stepper %}
{% step %}

#### Create the server

Create the server instance with the desired information model, as shown in [`create`](#create).
{% endstep %}

{% step %}

#### Handle client writes (onSet)

When a client sets a new `targetSpeed`, process it and confirm the change by calling `setValue`.

```yaml
# variablePath
Machine1/Status:targetSpeed
# listener
<callback>
```

{% endstep %}

{% step %}

#### Handle on-demand reads (onRequest)

When a client requests the `uptime`, calculate it inside the callback and provide it back via `setValue`.

```yaml
# variablePath
Machine1/Status:uptime
# listener
<callback>
```

{% endstep %}

{% step %}

#### Update internal state (setValue)

A flow that reads the machine's actual speed periodically updates the `currentSpeed` getter.

```yaml
# variablePath
Machine1/Status:currentSpeed
# value
1498
```

{% endstep %}

{% step %}

#### Start the server

After all handlers are configured, trigger `start`.
{% endstep %}
{% endstepper %}

## Tips and tricks

### Server update throttling

The internal notification processor throttles `onServerUpdate` events to a maximum of once per second. Rapid successive `setValue` updates apply to memory values instantly, but listeners tracking global server updates receive notifications aggregated at one-second intervals.

### Protocol and encryption

The local server operates with unencrypted communication profiles (`SecurityPolicy.None` and `MessageSecurityMode.None`). It does not support custom certificates or encrypted transport envelopes. Manage outer network security boundaries when routing client traffic across public infrastructure.

### Data type validation

The underlying engine strictly validates values passed to `setValue` against the information model schema. Input data types must comply with these parameters:

| Model data type                                     | Expected platform primitive                                      |
| --------------------------------------------------- | ---------------------------------------------------------------- |
| `boolean`                                           | Primitive JavaScript boolean values (`true` or `false`).         |
| `string`, `date`                                    | Textual strings. Dates must conform to standard ISO 8601 syntax. |
| `integer`, `bigint`, `float`, `double`, `timestamp` | Numeric values.                                                  |
| `arrayBoolean`, `arrayInteger`, `arrayString`, etc. | Standard arrays containing matching primitive types.             |


# Operating system (OS)

The operating system connector provides static functions to retrieve live performance metrics and hardware information from the host operating system. Use it to monitor CPU utilization, memory allocation, disk storage, network throughput, and running Docker containers.

Since all functions in this class are static, they do not manage state. You do not need to create an instance to use them.

## System metrics

### `cpuUsage`

Retrieves the current overall CPU utilization as a percentage.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>interval</code></td><td>The measurement window in milliseconds used to calculate utilization. Default 1000.</td><td>integer</td></tr></tbody></table>

#### Output

Returns a number representing the total CPU usage percentage.

#### Example

```yaml
# interval
2000
```

### `cpuCount`

Retrieves the total number of logical CPU cores available on the system.

#### Parameters

None.

#### Output

Returns an integer representing the core count.

### `loadAverage`

Retrieves system load averages for the past 1, 5, and 15 minutes, normalized by the total number of available logical CPU cores.

{% hint style="info" %}

#### Platform limitation

Load averages are a Unix-specific metric. On Windows, this function always returns `[0, 0, 0]`.
{% endhint %}

#### Parameters

None.

#### Output

Returns an array of three numbers representing the normalized system load averages.

### `driveInfo`

Retrieves capacity and utilization metrics for the primary disk drive.

#### Parameters

None.

#### Output

Returns an object containing disk storage statistics:

```json
{
  "totalGb": "930.85",
  "usedGb": "450.20",
  "freeGb": "480.65",
  "usedPercentage": 48.37,
  "freePercentage": 51.63
}
```

### `memInfo`

Retrieves resource allocation and utilization metrics for the physical memory.

#### Parameters

None.

#### Output

Returns an object containing physical RAM capacity and allocation statistics:

```json
{
  "totalMemMb": 16384,
  "usedMemMb": 8192,
  "freeMemMb": 8192,
  "freeMemPercentage": 50
}
```

### `netInfo`

Retrieves network input and output throughput statistics aggregated across active network interfaces.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>interval</code></td><td>The measurement window in milliseconds used to calculate network throughput. Default 1000.</td><td>integer</td></tr></tbody></table>

#### Output

Returns an object detailing input and output metrics in megabytes for each network interface alongside a combined total:

```json
{
  "total": {
    "inputMb": "0.15",
    "outputMb": "0.05"
  },
  "eth0": {
    "inputMb": "0.15",
    "outputMb": "0.05"
  }
}
```

#### Example

```yaml
# interval
1000
```

### `uptime`

Retrieves the total operational uptime of the operating system.

#### Parameters

None.

#### Output

Returns an object breaking down system uptime into chronological increments alongside the absolute duration in seconds:

```json
{
  "y": 0,
  "d": 14,
  "h": 6,
  "m": 32,
  "s": 15,
  "totalSeconds": 1233135
}
```

### `os`

Retrieves the platform name of the underlying operating system.

#### Parameters

None.

#### Output

Returns a string containing the operating system identifier (such as `Linux`, `macOS`, or `Windows_NT`).

### `hostname`

Retrieves the network hostname of the local system.

#### Parameters

None.

#### Output

Returns a string containing the system hostname.

## Container management

### `containerStats`

Retrieves live resource utilization and status metrics for all running Docker containers.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>socketPath</code></td><td>The file system path to the Docker daemon socket. Default <code>'/var/run/docker.sock'</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of objects detailing container execution statistics, processing allocations, and memory usage with inactive file cache overhead removed:

```json
[
  {
    "id": "a1b2c3d4e5f6",
    "name": "my-app-container",
    "state": "running",
    "status": "Up 2 weeks",
    "created": 1678886400,
    "usedMemory": "150.25 MiB",
    "availableMemory": "7.79 GiB",
    "memoryUsage": "1.89 %",
    "cpuUsage": "5.12 %",
    "numberCpus": 8
  }
]
```

### `containerInfo`

Retrieves configuration and state metadata profiles for all running Docker containers.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>socketPath</code></td><td>The file system path to the Docker daemon socket. Default <code>'/var/run/docker.sock'</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of detailed inspection objects containing container configuration profiles, layer settings, storage volume bindings, and network maps.


# RS-232/485

The RS-232/485 connector provides a unified interface to communicate with devices connected over a serial port, such as physical RS-232 and RS-485 interfaces, or USB-to-serial adapters. It scans system ports, configures connection parameters, and manages incoming and outgoing data streams.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can scan system ports, configure connection parameters, or manage data streams.

## Connection management

### `list`

Scans the host system and returns an array of all detected serial ports. Use this to locate valid port paths before creating an instance.

#### Parameters

None.

#### Output

Returns an array of objects containing detailed platform hardware information for each detected serial port.

#### Example

```json
[
  {
    "path": "COM3",
    "manufacturer": "Arduino LLC",
    "serialNumber": "12345",
    "pnpId": "USB\\VID_2341&PID_0043\\12345",
    "locationId": "Port_#0003.Hub_#0001",
    "productId": "0043",
    "vendorId": "2341"
  }
]
```

### `create`

Creates an instance configured for a specific serial port. The connector preserves these properties but delays opening the physical hardware port until you run `open`.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>path</code></td><td>The file system path of the target serial port (such as <code>/dev/ttyUSB0</code> on Linux or <code>COM3</code> on Windows).</td><td>string</td></tr><tr><td></td><td><code>baudRate</code></td><td>The serial communication speed in bits per second. Supported standard values include 110, 300, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, or 115200. Default 9600.</td><td>integer</td></tr><tr><td></td><td><code>dataBits</code></td><td>The number of data bits per character frame (5, 6, 7, or 8). Default 8.</td><td>integer</td></tr><tr><td></td><td><code>stopBits</code></td><td>The number of stop bits to signal the end of a character frame (1, 1.5, or 2). Default 1.</td><td>number</td></tr><tr><td></td><td><code>parity</code></td><td>The parity error-checking mode (<code>none</code>, <code>even</code>, <code>mark</code>, <code>odd</code>, or <code>space</code>). Default 'none'.</td><td>string</td></tr><tr><td></td><td><code>lock</code></td><td>Prevents other system processes from gaining control of the port. Windows does not support disabling this. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>rtscts</code></td><td>Enables Ready to Send / Clear to Send (RTS/CTS) hardware handshaking flow control. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>xon</code></td><td>Enables XON software flow control. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>xoff</code></td><td>Enables XOFF software flow control. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>xany</code></td><td>Enables XANY software flow control, which allows any received character to restart transmission. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>hupcl</code></td><td>Drops the Data Terminal Ready (DTR) hardware line when closing the connection. Default true.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns the name of the created instance.

#### Example

```yaml
# options
path: COM3
baudRate: 9600
dataBits: 8
parity: none
stopBits: 1
```

### `open`

Opens the communication channel to the serial port defined in the configuration.

#### Parameters

None.

#### Output

Returns `true` when the connection succeeds. Throws an error on failure.

### `isOpen`

Checks whether the communication channel to the serial port is open.

#### Parameters

None.

#### Output

Returns `true` if the channel is open, or `false` if it is not.

### `changeBaudRate`

Updates the communication speed dynamically for an active, open serial connection.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>baudRate</code></td><td>The new baud rate (such as 19200 or 115200).</td><td>integer</td></tr></tbody></table>

#### Output

Returns `true` if the baud rate updates successfully. Throws an error on failure.

#### Example

```yaml
# baudRate
115200
```

### `close`

Closes the active serial connection.

#### Parameters

None.

#### Output

Returns `true` on successful disconnection. Ongoing write operations automatically fail if the connection drops before they finish.

### `delete`

Removes the instance and its configuration.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To communicate with the device again, you must create a new instance.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Data operations

### `write`

Transmits a text string across the active serial interface and pauses execution until the port transmits all data. To insert control characters, use `<CR>` for carriage return (`\r`), `<LF>` for line feed (`\n`), and `<CRLF>` for both (`\r\n`).

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>data</code></td><td>The text string to transmit. Supports control tokens like <code>&#x3C;CRLF></code>.</td><td>string</td></tr><tr><td><code>suffix</code></td><td>An optional string appended automatically to the end of the text. Default empty string.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true` when all data transmits completely. Throws an error on failure.

#### Example

```yaml
# data
GET_DATA
# suffix
<CRLF>
```

### `read`

Retrieves a specific number of raw bytes from the incoming receive buffer. To monitor incoming traffic asynchronously, use `onData` instead of polling with this function.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>size</code></td><td>The number of bytes to retrieve from the receive buffer.</td><td>integer</td></tr></tbody></table>

#### Output

Returns a decoded string containing the retrieved bytes, or `null` if the buffer does not contain the requested number of bytes.

### `onData`

Registers a named observer that parses the incoming serial data stream and triggers a callback when a complete message arrives. Use only one of the three parsing strategies. If several are set, `timeout` takes precedence over `byteLength` over `delimiter`.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>name</code></td><td></td><td>A unique label to identify this stream parser.</td><td>string</td></tr><tr><td><code>handler</code></td><td></td><td>The callback evaluated on payload match. Receives the parsed string payload.</td><td>callback</td></tr><tr><td><code>parserOptions</code></td><td><code>delimiter</code></td><td>Emits the accumulated stream immediately when encountering this character sequence. Recognizes control tokens like <code>&#x3C;LF></code> or <code>&#x3C;CRLF></code>. Default <code>&#x3C;LF></code>.</td><td>string</td></tr><tr><td></td><td><code>timeout</code></td><td>Emits the accumulated data after detecting a communication silence of this duration in milliseconds.</td><td>integer</td></tr><tr><td></td><td><code>byteLength</code></td><td>Emits the data block when the incoming stream reaches this fixed size in bytes.</td><td>integer</td></tr></tbody></table>

#### Output

Returns `true` when the observer registers successfully, or nothing if an observer with that name already exists.

#### Examples

**Example 1: Delimiter text parsing**

```yaml
# name
line_handler
# handler
<callback>
# parserOptions
delimiter: <LF>
```

**Example 2: Inter-byte timeout burst parsing**

```yaml
# name
burst_handler
# handler
<callback>
# parserOptions
timeout: 50
```

**Example 3: Fixed byte length parsing**

```yaml
# name
packet_handler
# handler
<callback>
# parserOptions
byteLength: 16
```

### `onError`

Registers an observer that triggers whenever the serial channel encounters a hardware or connection error.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>name</code></td><td>A unique identification label for this error observer.</td><td>string</td></tr><tr><td><code>handler</code></td><td>The callback triggered when a connector exception occurs. Receives the error object.</td><td>callback</td></tr></tbody></table>

#### Output

Returns `true` when the observer registers successfully, or nothing if an observer with that name already exists.

#### Example

```yaml
# name
my_error_handler
# handler
<callback>
```


# Sap Digital Manufacturing

Beta Feature

{% hint style="info" %}
This connector is a beta feature.
{% endhint %}

The SAP Digital Manufacturing connector (`SapDigitalManufacturing`) communicates with the SAP Digital Manufacturing Cloud API. It manages the OAuth2 authentication flow and lets you read data from REST endpoints or query Managed Data Objects (MDO) via OData.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can manage connection states and execute data transactions.

## Connection and lifecycle

### `create`

Creates an instance configured to communicate with a specific SAP Digital Manufacturing tenant API.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>publicApiEndpoint</code></td><td>The base URL of the target digital manufacturing API, such as <code>https://api.eu20.dmc.cloud.sap</code>.</td><td>string</td></tr><tr><td></td><td><code>authUrl</code></td><td>The URL of the OAuth token endpoint.</td><td>string</td></tr><tr><td></td><td><code>clientId</code></td><td>The OAuth client ID.</td><td>string</td></tr><tr><td></td><td><code>clientSecret</code></td><td>The OAuth client secret.</td><td>string</td></tr></tbody></table>

{% hint style="info" %}
Right-click the `options` input and mark it as a secret to mask the credentials.
{% endhint %}

#### Output

Returns the name of the created instance.

#### Example

```yaml
# options
publicApiEndpoint: https://api.eu20.dmc.cloud.sap
authUrl: https://my-subaccount.authentication.eu20.hana.ondemand.com/oauth/token
clientId: sb-abc123def456!xyz
clientSecret: my-very-secret-key-!@#$
```

### `canCommunicate`

Checks whether communication with the cloud API is operational and authenticated.

#### Parameters

None.

#### Output

Returns `true` if communication succeeds, or `false` if it fails.

### `delete`

Removes the instance and its connection configuration.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To communicate with the API again, you must trigger `create` anew.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Data operations

### `read`

Executes a GET request against standard SAP Digital Manufacturing REST endpoints.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>path</code></td><td>The relative API path of the endpoint, such as <code>/order/v1/orders</code>.</td><td>string</td></tr><tr><td><code>params</code></td><td>Query parameters specified as key-value pairs appended to the URL.</td><td>object</td></tr></tbody></table>

#### Output

Returns a parsed JSON object containing the API response. Throws an error on failure.

#### Examples

**Example 1: Read work centers**

```yaml
# path
/resource/v1/workcenters
# params
plant: 1710
```

*Generated URL: `.../resource/v1/workcenters?plant=1710`*

**Example 2: Read production order details**

```yaml
# path
/order/v1/orders
# params
plant: 1710
order: '1000456'
```

*Generated URL: `.../order/v1/orders?plant=1710&order=1000456`*

### `readMdo`

Queries a Managed Data Object (MDO) via OData to read custom master data tables.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>entityPath</code></td><td>The OData entity path for the target object, such as <code>/ToolMDOs</code>.</td><td>string</td></tr><tr><td><code>query</code></td><td>An OData query string to filter, sort, or select fields, such as <code>?$top=10</code>. Default empty string.</td><td>string</td></tr></tbody></table>

#### Output

Returns a parsed JSON object containing the OData response. Throws an error on failure.

#### Examples

**Example 1: Read entries with a top limit**

```yaml
# entityPath
/ToolMDOs
# query
?$top=5
```

*Generated URL: `.../ToolMDOs?$top=5`*

**Example 2: Read a specific entry by identifier**

```yaml
# entityPath
/ToolMDOs('TOOL-001')
```

*Generated URL: `.../ToolMDOs('TOOL-001')`*

**Example 3: Filter entries and select specific fields**

```yaml
# entityPath
/ToolMDOs
# query
?$filter=toolType eq 'DRILL'&$select=toolId,description,wear
```

*Generated URL: `.../ToolMDOs?$filter=toolType%20eq%20'DRILL'&$select=toolId,description,wear`*


# Siemens S7

The Siemens S7 connector (`S7`) communicates directly with Siemens S7 programmable logic controllers (PLCs). It lets you read and write PLC memory areas using raw memory addresses or human-readable variable aliases.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can manage connection states and configure variable polling.

## TIA Portal configuration

Before connecting, retrieve the IP address, rack number, and slot number from your TIA Portal project configuration.

### IP address

Select the PLC in the TIA Portal project tree. Open the Properties tab below and navigate to **PROFINET interface > Ethernet addresses** to identify the configured IP address.

### Rack and slot

S7-1200 and S7-1500 controllers typically use rack 0 and slot 1. For classic S7-300 and S7-400 hardware, open **Device configuration** to verify the CPU position. The processor is usually on rack 0, slot 2.

### Enable PUT and GET communication

Configure the controller to permit PUT and GET communication:

1. Right-click the controller and select **Properties**.
2. Navigate to **Protection & Security > Connection mechanisms**.
3. Select **Permit access with PUT/GET communication from remote partner**.
4. Compile and download the updated hardware configuration to the PLC.

## Connection management

{% hint style="info" %}
Typically you first install the Siemens S7 connector within an [Agent](/app-builder/build-backend/agents). That way you can connect your cloud platform to your on-premises shopfloor PLCs.
{% endhint %}

### `create`

Creates an S7 client instance. The connection details follow in `connect`.

#### Parameters

None.

#### Output

Returns the name of the created instance.

### `connect`

Establishes a connection to the target PLC.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>host</code></td><td>The IP address or hostname of the PLC.</td><td>string</td></tr><tr><td></td><td><code>port</code></td><td>The communication port of the PLC. Default 102.</td><td>integer</td></tr><tr><td></td><td><code>rack</code></td><td>The physical rack position of the CPU. Default 0.</td><td>integer</td></tr><tr><td></td><td><code>slot</code></td><td>The slot position of the CPU. Default 1.</td><td>integer</td></tr><tr><td></td><td><code>timeout</code></td><td>The connection timeout in milliseconds. Default 5000.</td><td>integer</td></tr></tbody></table>

#### Output

Returns `true` when the connection succeeds. Throws an error on failure.

#### Example

```yaml
# options
host: 192.168.0.1
port: 102
rack: 0
slot: 1
```

### `disconnect`

Terminates the active TCP connection session with the PLC.

#### Parameters

None.

#### Output

Returns `true` on successful disconnection, including when no connection exists.

### `getStatus`

Queries the current connection state of the instance.

#### Parameters

None.

#### Output

Returns `'disconnected'`, `'connecting'`, or `'connected'`.

### `delete`

Removes the instance and its configuration.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To communicate with the PLC again, you must create a new instance.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Variable addressing and dictionary

The address dictionary is an optional convenience layer. Functions like `addItems` and `writeItems` accept aliases, raw PLC addresses, or a mix of both: the connector first checks whether a string is an alias in the dictionary and otherwise treats it as a direct address. See [Memory address syntax](#memory-address-syntax) for the address format.

### `setAddressDictionary`

Configures the connector instance with an address dictionary. This lets you map human-readable aliases to raw PLC addresses for use in subsequent polling or data transactions.

{% hint style="danger" %}

#### Polling configuration reset

Registering a new address dictionary flushes all items from the read monitoring queue. Establish the dictionary before adding items to the polling queue.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>dictionary</code></td><td>An object mapping human-readable aliases to raw PLC addresses. Default {}.</td><td>object</td></tr></tbody></table>

#### Output

Returns `true` on successful registration.

#### Example

```yaml
# dictionary
MOTOR_SPEED: 'DB1,REAL4'
E_STOP_PRESSED: 'I0.0'
CONVEYOR_RUNNING: 'Q4.1'
PROCESS_STEP_COMPLETE: 'M10.5'
```

### `showAddressDictionary`

Retrieves the active address dictionary.

#### Parameters

None.

#### Output

Returns an object containing the registered address aliases.

## Polling list configuration

### `addItems`

Registers variable addresses or dictionary aliases in the background read polling loop.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>items</code></td><td>A variable address, alias, or array of strings to add to the polling queue.</td><td>array or string</td></tr></tbody></table>

#### Output

Returns `true` on success.

#### Examples

**Example 1: Register raw memory addresses**

```yaml
# items
- 'DB1,X0.0'
- 'MW10'
```

**Example 2: Register mixed aliases and raw addresses**

```yaml
# items
- MOTOR_SPEED
- 'DB5,X1.5'
```

### `removeItems`

Removes specific variables from the background polling loop.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>items</code></td><td>A variable address, alias, or array of strings to remove from the polling queue. If omitted, removes all variables.</td><td>array or string</td></tr></tbody></table>

#### Output

Returns `true` on success.

#### Example

```yaml
# items
- E_STOP_PRESSED
```

### `removeAllItems`

Removes all registered variables from the active background polling queue.

#### Parameters

None.

#### Output

Returns `true` on success.

### `showAllItems`

Lists all variables currently in the background polling queue.

#### Parameters

None.

#### Output

Returns an array of all raw memory paths or dictionary aliases in the polling queue.

## Data operations

### `readAllItems`

Reads the current values of all variables in the polling queue.

#### Parameters

None.

#### Output

Returns an object containing the current values of all registered variables. Keys map to the variable names or aliases. Throws an error if reading fails.

```json
{
  "MOTOR_SPEED": 1499.98,
  "DB10,X20.4": true
}
```

### `writeItems`

Writes data updates to one or more variables on the PLC.

{% hint style="warning" %}

#### Concurrent write constraint

The connector executes one write operation at a time. Sending concurrent writes while a write is in progress causes a write rejection error.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>items</code></td><td>A variable address, alias, or array of strings to update.</td><td>array or string</td></tr><tr><td><code>values</code></td><td>The value or array of values to write. Ensure the array length and order match the <code>items</code> parameter.</td><td>array or any</td></tr></tbody></table>

#### Output

Returns `true` when the write succeeds. Throws an error on failure.

#### Examples

**Example 1: Write a single variable**

```yaml
# items
CONVEYOR_RUNNING
# values
true
```

**Example 2: Write multiple variables**

```yaml
# items
- MOTOR_SPEED
- 'DB1,X0.7'
# values
- 1500
- true
```

## Deprecated functions

The following functions are maintained for backward compatibility. Update your App logic to use the recommended replacements.

| Deprecated function  | Use instead  |
| -------------------- | ------------ |
| `initiateConnection` | `connect`    |
| `dropConnection`     | `disconnect` |

## Tips and tricks

### Memory address syntax

Format memory address strings as `AREA,TYPE<BYTE_OFFSET>[.BIT_OR_LENGTH]`.

#### Memory areas

* `DB<number>` (Data Block) – Shared memory registers for logic, recipes, and process variables (such as `DB1,REAL4`).
* `I` (Inputs) – Read-only registers tracking physical digital and analog inputs.
* `Q` (Outputs) – Control registers driving physical outputs.
* `M` (Merkers/Internal Memory) – Internal processor flags and global staging variables.

#### Data layouts

* Boolean (`X`) – Single-bit fields (such as `DB1,X0.0`).
* Byte (`B`) – 8-bit integer values from 0 to 255.
* Char Array (`C`) – Alphanumeric sequences (such as `DB1,C20.10` for 10 sequential characters).
* String (`S`) – Siemens S7 strings with standard length headers.
* Integer (`INT`) – 16-bit signed integers.
* Word (`WORD`) – 16-bit unsigned integers.
* Double Int (`DINT`) – 32-bit signed integers.
* DWord (`DWORD`) – 32-bit unsigned integers.
* Real (`REAL`) – 32-bit floating-point decimals (such as `DB1,REAL14`).

### Error "Object does not exist"

This error means you are reading or writing a Data Block (`DB`) that either does not exist or is too small in the PLC. Ensure the DB number is correct and that its size in TIA Portal is large enough to hold all your variables.

### Handling scrambled strings

If characters returned by the `S` string type appear scrambled or out of order, the PLC might store a raw character array instead of a standard S7 string. S7 strings contain a header that defines capacity. If the PLC stores raw characters without a header, use the `C` (Char Array) type to read the text (such as `DB1,C0.16`).

### Reading TIME values

S7 processors store `TIME` values as signed 32-bit integers tracking milliseconds. To read or write these values, use the `DINT` data type.


# Zebra RFID IoT

The Zebra RFID IoT connector (`ZebraRfidIot`) controls and receives data from Zebra fixed RFID readers (such as the FX7500, FX9600, or ATR7000). Instead of managing direct physical serial wires or proprietary connections, the connector exchanges structured events and commands asynchronously over the platform's internal MQTT broker by communicating with the Zebra IoT Connector (ZIOTC) service running locally on the reader.

This connector requires [instance creation](/app-builder/build-backend/functions/connectors#instance-creation) before you can send commands and receive events.

## Architecture and setup

The communication line links the physical hardware reader directly to your App flows through an intermediary messaging loop:

`Zebra RFID Reader` → `Zebra IoT Connector (On-Reader Service)` → `Platform MQTT Broker` → `Your App Flow`

To establish communication, configure the ZIOTC service interface using the reader's local web administration console (located under communication > Zebra IoT Connector) to append uniform topic suffixes matching these paths:

* Management Event Topic: `<Base Topic>/m-evt`
* Data Event Topic: `<Base Topic>/d-evt`
* Management Request Topic: `<Base Topic>/m-req`
* Control Request Topic: `<Base Topic>/c-req`

If your reader firmware requires explicit response topic declarations, add these routes:

* Management Response Topic: `<Base Topic>/m-res`
* Control Response Topic: `<Base Topic>/c-res`

## Connection management

### `create`

Creates a Zebra IoT connector instance for a specific reader, identified by its base MQTT topic. The base topic is required.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>baseTopic</code></td><td>The root MQTT topic of the target reader, as configured in its ZIOTC interface settings.</td><td>string</td></tr></tbody></table>

#### Output

Returns the name of the created instance.

#### Example

```yaml
# baseTopic
my-account/zebra/atr7000/12345
```

### `isConnected`

Queries whether the underlying MQTT communication channel to the broker layer is open and active.

#### Parameters

None.

#### Output

Returns `true` if the communication link is operational, or `false` if it is not.

### `delete`

Removes the instance and all registered listeners.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To communicate with the device again, you must create a new instance.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Reader status and configuration

The functions in this section and in [Control and operations](#control-and-operations) send a command to the reader and throw an error if the reader does not respond within 6 seconds.

### `getVersion`

Retrieves the hardware and system firmware version details reported by the connected reader.

#### Parameters

None.

#### Output

Returns an object containing hardware and firmware version metadata.

### `getNetwork`

Retrieves the current network interface settings running on the reader.

#### Parameters

None.

#### Output

Returns an object containing active network parameters, including local IP addresses and MAC addresses.

### `getConfig`

Retrieves the operational parameter configuration block currently deployed to the reader.

#### Parameters

None.

#### Output

Returns an object containing the active configuration settings of the reader.

### `getStatus`

Queries the active status of the physical reader hardware.

#### Parameters

None.

#### Output

Returns an object detailing diagnostic hardware conditions and state parameters.

### `getLed`

Queries the color state configuration displayed on the reader's status indicator LED.

#### Parameters

None.

#### Output

Returns an object detailing the active LED color and visualization status.

### `getMode`

Retrieves the tag scanning mode configuration currently running on the device.

#### Parameters

None.

#### Output

Returns an object containing the active scan mode and its parameters.

### `getLogConfiguration`

Queries the system logging rules and level configurations mapped to the reader.

#### Parameters

None.

#### Output

Returns an object detailing active logging levels and event metrics.

## Control and operations

### `setLed`

Sets the status color displayed on the physical reader's indicator LED.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>color</code></td><td>The target color value to apply (<code>off</code>, <code>red</code>, <code>amber</code>, or <code>green</code>).</td><td>string</td></tr><tr><td><code>seconds</code></td><td>The duration in seconds for the color state to remain active.</td><td>integer</td></tr><tr><td><code>flash</code></td><td>Forces an intermittent flashing animation when set to <code>true</code>.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns `true` when the reader confirms the command.

#### Example

```yaml
# color
green
# seconds
5
# flash
true
```

### `setMode`

Configures the reader's operational mode, including antennas, filters, and metadata collection. See [Tracking mode selection](#tracking-mode-selection) for choosing the right `type`.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="200">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>type</code></td><td>The mode of operation: <code>SIMPLE</code>, <code>INVENTORY</code>, <code>PORTAL</code>, <code>CONVEYOR</code>, <code>CUSTOM</code>, or <code>DIRECTIONALITY</code>.</td><td>string</td></tr><tr><td></td><td><code>modeSpecificSettings</code></td><td>Mode-specific settings (such as <code>inventorySettings</code> or <code>portalSettings</code>).</td><td>object</td></tr><tr><td></td><td><code>environment</code></td><td>The operating environment: <code>LOW_INTERFERENCE</code>, <code>HIGH_INTERFERENCE</code>, <code>VERY_HIGH_INTERFERENCE</code>, <code>AUTO_DETECT</code>, or <code>DEMO</code>. Default <code>HIGH_INTERFERENCE</code>.</td><td>string</td></tr><tr><td></td><td><code>antennas</code></td><td>An array of antenna port integers to use. Uses all ports if omitted.</td><td>array</td></tr><tr><td></td><td><code>filter</code></td><td>A tag ID filter object (such as an EPC prefix). No filter if omitted.</td><td>object</td></tr><tr><td></td><td><code>transmitPower</code></td><td>The transmit power in dBm, as a single number or an array of numbers. Default 27 (36 dBm EIRP for ATR).</td><td>any</td></tr><tr><td></td><td><code>antennaStopCondition</code></td><td>Stop condition(s) for antennas, as a single object or an array. Defaults to a single inventory round.</td><td>any</td></tr><tr><td></td><td><code>query</code></td><td>Gen2 query parameters.</td><td>object</td></tr><tr><td></td><td><code>selects</code></td><td>Gen2 select parameters: an array of select objects (applied to all antennas) or an array of arrays (one per antenna).</td><td>array</td></tr><tr><td></td><td><code>delayAfterSelects</code></td><td>The duration in milliseconds (0 to 65) to wait after the final select before issuing a query.</td><td>integer</td></tr><tr><td></td><td><code>accesses</code></td><td>Gen2 access commands (read, write, lock, kill): an array of commands or an array of arrays (one per antenna).</td><td>array</td></tr><tr><td></td><td><code>delayBetweenAntennaCycles</code></td><td>An object defining a delay between antenna cycles if no tags are read.</td><td>object</td></tr><tr><td></td><td><code>tagMetaData</code></td><td>An array of metadata to report: strings such as <code>ANTENNA</code>, <code>RSSI</code>, <code>PHASE</code>, <code>CHANNEL</code>, <code>SEEN_COUNT</code>, <code>PC</code>, <code>XPC</code>, <code>CRC</code>, <code>EPC</code>, <code>TID</code>, <code>USER</code>, <code>MAC</code>, <code>HOSTNAME</code>, <code>TAGURI</code>, <code>EPCURI</code>, partial reads such as <code>EPC[1,3-5]</code>, or objects such as <code>{ userDefined: ... }</code>.</td><td>array</td></tr><tr><td></td><td><code>radioStartConditions</code></td><td>An object controlling when the radio starts inventorying after a start command.</td><td>object</td></tr><tr><td></td><td><code>radioStopConditions</code></td><td>An object controlling when an ongoing operation completes.</td><td>object</td></tr><tr><td></td><td><code>reportFilter</code></td><td>An object controlling when and how often a tag is reported. Cannot be set in <code>INVENTORY</code> mode.</td><td>object</td></tr><tr><td></td><td><code>rssiFilter</code></td><td>An object filtering tags by RSSI threshold. FX9600 only.</td><td>object</td></tr><tr><td></td><td><code>beams</code></td><td>An array of beam objects to use. ATR7000 only.</td><td>array</td></tr></tbody></table>

#### Output

Returns `true` when the reader confirms the configuration. Throws an error if `type` is missing.

#### Examples

**Example 1: Basic inventory polling configuration**

```yaml
# options
type: INVENTORY
antennas:
  - 1
  - 2
transmitPower: 30.1
antennaStopCondition:
  - type: DURATION
    value: 500
tagMetaData:
  - RSSI
  - PC
```

**Example 2: Triggered portal filtering configuration**

```yaml
# options
type: PORTAL
environment: LOW_INTERFERENCE
antennas:
  - 1
transmitPower: 25
filter:
  prefix: '3008'
tagMetaData:
  - EPC
  - TID
  - RSSI
reportFilter:
  duration: 0
```

### `start`

Instructs the remote reader to start radio sweeps and stream tag records over data event channels.

#### Parameters

None.

#### Output

Returns `true` when the reader confirms the command.

### `stop`

Instructs the remote reader to halt active radio polling sweeps and pause incoming tag data streams.

#### Parameters

None.

#### Output

Returns `true` when the reader confirms the command.

## Event listeners

### `onHeartbeatEvent`

Registers a listener for the periodic heartbeat events of the reader, which indicate that it is still online.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>listener</code></td><td>The callback evaluated on every heartbeat. Receives the heartbeat event object.</td><td>callback</td></tr></tbody></table>

#### Output

Returns the string `subscribed` to confirm listener registration.

#### Example

```yaml
# listener
<callback>
```

### `onErrorEvent`

Registers a listener for error events reported by the reader.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>listener</code></td><td>The callback evaluated on every error event. Receives the error event object.</td><td>callback</td></tr></tbody></table>

#### Output

Returns the string `subscribed` to confirm listener registration.

#### Example

```yaml
# listener
<callback>
```

### `onDataEvent`

Registers a named handler that receives RFID tag data. This is the primary way of getting tag reads and includes options for aggregating and filtering the data.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>name</code></td><td></td><td>A unique name identifying this data handler.</td><td>string</td></tr><tr><td><code>handler</code></td><td></td><td>The callback receiving the tag data and the message count. With aggregation, it receives an array of unique tag messages; without, the single message. After the <code>clearAfter</code> interval of inactivity it fires again with an empty result and count 0.</td><td>callback</td></tr><tr><td><code>options</code></td><td><code>scanDuration</code></td><td>The time in milliseconds to collect unique tags before the callback fires with the batch. Set to 0 to deliver every read instantly. Default 0.</td><td>integer</td></tr><tr><td></td><td><code>clearAfter</code></td><td>The time in milliseconds of inactivity after which the internal list of seen tags clears automatically. Set to 0 to never clear. Default 10000.</td><td>integer</td></tr><tr><td></td><td><code>aggregate</code></td><td>Reports a batch of unique tags seen during <code>scanDuration</code> when <code>true</code>, or every single read immediately when <code>false</code>. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>antenna</code></td><td>If set, only tags read by this antenna port are reported.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the string `subscribed` to confirm listener registration.

#### Examples

**Example 1: Streaming data delivery without aggregation**

```yaml
# name
immediate_reporter
# handler
<callback>
# options
aggregate: false
```

**Example 2: Compiled window aggregation**

This collects all unique tags seen in a 2-second window and then fires the handler with the complete batch:

```yaml
# name
batch_reporter
# handler
<callback>
# options
scanDuration: 2000
aggregate: true
```

### `clearData`

Clears the internal cache of seen tags for a specific data handler, without waiting for the `clearAfter` interval. The handler fires once with an empty result.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>name</code></td><td>The name of the <code>onDataEvent</code> handler to clear.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true`, including when no handler with that name exists.

#### Example

```yaml
# name
batch_reporter
```

### `removeDataListener`

Unregisters a data listener and clears its pending timers.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>name</code></td><td>The name of the data listener to remove.</td><td>string</td></tr></tbody></table>

#### Output

Returns the string `unsubscribed`, or `not found` if no listener with that name exists.

#### Example

```yaml
# name
batch_reporter
```

## Tips and tricks

### Tracking mode selection

* `SIMPLE`: Sends a data event immediately for every tag read. Use this for real-time presence detection.
* `INVENTORY`: Groups reads into periodic batch summaries with statistics. Use this for counting assets.
* `PORTAL`: Links with physical sensors to track tag bursts. Use this for doorways and logistics checkpoints.
* `CONVEYOR`: Optimizes for high-speed line sweeps where tags pass in fractions of a second.
* `CUSTOM`: Allows fine-grained control over low-level radio parameters for advanced scenarios.


# Storage

The storage category contains the classes that persist and manage your App data. Heisenware includes two internal databases (PostgreSQL and InfluxDB) to store data automatically. These same classes also connect to external database servers.

## Relational storage

Use the [Relational database](/app-builder/build-backend/functions/storage/relational-database) class for structured data such as user profiles, orders, or inventory.

Every account includes a pre-configured instance named `internal-postgres`. It runs a managed PostgreSQL database, letting you drag database functions onto the canvas to store data immediately.

To connect an existing SQL server instead (PostgreSQL, MySQL, MariaDB, MSSQL, or SQLite), open the Function Explorer, select the relational database class, and call its `create` function. Enter your connection details to generate a new, standalone database instance.

## Timeseries storage

Use the [Timeseries database](/app-builder/build-backend/functions/storage/timeseries-database) class for high-frequency data such as sensor readings or machine telemetry.

Every account includes a managed InfluxDB instance named `internal-influx`. To populate it, attach a [recorder extension node](/app-builder/build-backend/extension-nodes/recorder) to any function output to store every value with no configuration. Use the timeseries database functions to read and query this recorded data.

To connect an external InfluxDB server instead, open the Function Explorer, select the timeseries database class, and call its `create` function to generate a new instance.

## In-memory storage

For temporary data that lives only during a session and does not save to disk, use these lightweight classes:

* [Data store](/app-builder/build-backend/functions/storage/data-store): Simple state management.
* [Circular buffer](/app-builder/build-backend/functions/storage/circular-buffer): Rolling data, such as the last 100 values for a live chart.


# Relational database

The relational database connector communicates with SQL databases (PostgreSQL, MySQL, MariaDB, MSSQL, SQLite, Oracle, and Snowflake) without writing raw SQL. You can define tables, insert and query rows, model relationships, and track changes with a consistent set of functions.

## Quick start: the internal PostgreSQL instance

Heisenware provides a pre-initialized SQL database called `internal-postgres`. It is globally available and ready for use. Pick functions from inside `internal-postgres` to make use of it.

<figure><img src="/files/XN06rGrHIePlF1hzs1UR" alt=""><figcaption></figcaption></figure>

## Connecting an external database

To connect an external database, use the [`create`](#create) function. How you configure it depends on where the database is located:

* **Cloud or public database**: If the database is accessible over the internet, create the instance directly in your App backend.
* **Local database (via Agent)**: If the database sits inside a private network (such as on a shopfloor server), deploy an [Agent](/app-builder/build-backend/agents) in that network first and create the database instance within that Agent.

{% hint style="info" %}
Whether you use the internal database or an external connection, the functions for querying, inserting, and managing data are identical.
{% endhint %}

## Connection and database management

### `create`

Initializes the connection to an external database.

{% hint style="info" %}
Skip this step for `internal-postgres`. It is already instantiated for you.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>dialect</code></td><td>The database dialect: <code>postgres</code>, <code>mysql</code>, <code>mariadb</code>, <code>mssql</code>, <code>sqlite</code>, <code>oracle</code>, or <code>snowflake</code>.</td><td>string</td></tr><tr><td></td><td><code>database</code></td><td>The name of the database.</td><td>string</td></tr><tr><td></td><td><code>username</code></td><td>The username for authentication.</td><td>string</td></tr><tr><td></td><td><code>password</code></td><td>The password for authentication.</td><td>string</td></tr><tr><td></td><td><code>host</code></td><td>The hostname or IP address of the database server.</td><td>string</td></tr><tr><td></td><td><code>port</code></td><td>The port number. Default is the standard port of the dialect.</td><td>integer</td></tr><tr><td></td><td><code>ssl</code></td><td>Uses SSL for the connection when <code>true</code>. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>sqlLogging</code></td><td>Logs all SQL statements when <code>true</code>. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>rawOnly</code></td><td>Skips the database introspection for instant startup when <code>true</code>. Use when you only need <code>executeSql</code>.</td><td>boolean</td></tr></tbody></table>

{% hint style="info" %}
Right-click the `options` input and mark it as a secret to mask the password.
{% endhint %}

#### Example

```yaml
# options
dialect: 'postgres'
database: 'mydb'
username: 'user'
password: 'pass'
host: 'localhost'
ssl: true
```

#### Output

Returns the name of the created instance.

### `isConnected`

Checks whether the database connection is currently active.

#### Parameters

None.

#### Output

Returns `true` if connected, or `false` if it is not.

### `getAllTables`

Retrieves all tables that exist in the database.

#### Parameters

None.

#### Output

Returns an array of table name strings.

### `reset`

Drops and recreates the entire database.

{% hint style="danger" %}

#### Irreversible action

This permanently deletes all tables and all data in the database. You cannot undo this action.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` if the reset succeeds.

### `delete`

Removes the instance and its connection configuration.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To communicate with the database again, you must create a new instance.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Schema and table definition

### `defineTable`

Defines a table schema. If the table does not exist, the function creates it. If it exists, the function adds any new fields.

Unless you define a custom primary key, the function automatically adds these fields:

* `id`: The table's primary key. A UUID on PostgreSQL, an auto-incrementing integer on other dialects.
* `createdAt`: A timestamp recording when the row was created.
* `updatedAt`: A timestamp tracking the last modification of the row.

{% hint style="info" %}
When running inside an Agent, the database disables the automatic `createdAt` and `updatedAt` timestamps.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>name</code></td><td></td><td>The name of the table (such as <code>users</code>).</td><td>string</td></tr><tr><td><code>fields</code></td><td></td><td>The table columns. Keys are the field names in camelCase. Values are either a data type string or a configuration object. Supported types: <code>string</code>, <code>text</code>, <code>integer</code>, <code>bigint</code>, <code>float</code>, <code>double</code>, <code>number</code>, <code>boolean</code> (alias <code>bool</code>), <code>date</code>, <code>uuid</code>, <code>json</code>, <code>jsonb</code>, <code>file</code>, <code>uniquestring</code>, <code>uniqueinteger</code>, <code>uniquebiginteger</code>. Unknown types fall back to <code>string</code>.</td><td>object</td></tr><tr><td><code>options</code></td><td><code>auditLog</code></td><td>Records all changes to this table when <code>true</code>. Replaces the deprecated <code>trackHistory</code>.</td><td>boolean</td></tr></tbody></table>

{% hint style="info" %}
Use English and camelCase for table and field names (such as `firstName` or `dateOfBirth`). Avoid spaces, dashes, and other special characters. When using PostgreSQL, prefer the `jsonb` type for JSON data: it is more efficient and allows nested properties in filter expressions.
{% endhint %}

#### Examples

**Example 1: Simple table**

```yaml
# name
users
# fields
name: string
email: uniquestring
age: integer
```

**Example 2: Table with custom primary key and JSONB**

```yaml
# name
products
# fields
id: { type: string, primaryKey: true }
name: string
price: number
specs: jsonb
```

{% hint style="warning" %}

#### Custom primary key naming

Always use `id` as the name of the primary key, even when overriding the default. Other names can cause unexpected behavior.
{% endhint %}

### Advanced field configuration

For more control, provide an object as a field's value with these properties:

<table><thead><tr><th width="150">Property</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>type</code></td><td>The data type string (such as <code>string</code> or <code>integer</code>). Required.</td><td>string</td></tr><tr><td><code>primaryKey</code></td><td>Sets this field as the primary key, overriding the default <code>id</code> field.</td><td>boolean</td></tr><tr><td><code>unique</code></td><td>Ensures all values in this column are unique. Assign the same arbitrary string to several fields to make their combination unique.</td><td>boolean or string</td></tr><tr><td><code>allowNull</code></td><td>Allows null values when <code>true</code>. Set to <code>false</code> to require a value.</td><td>boolean</td></tr><tr><td><code>defaultValue</code></td><td>A default value used if none is provided: a literal (such as <code>active</code> or <code>0</code>) or a special value like <code>NOW</code> for the current time.</td><td>any</td></tr><tr><td><code>autoIncrement</code></td><td>Automatically increments an integer primary key for each new row.</td><td>boolean</td></tr><tr><td><code>validate</code></td><td>Adds validation constraints (such as <code>{ isEmail: true, max: 23 }</code>).</td><td>object</td></tr></tbody></table>

**Example 1: Advanced table with constraints**

```yaml
# name
employees
# fields
employeeId: { type: integer, primaryKey: true, autoIncrement: true }
email: { type: string, allowNull: false, unique: true }
status: { type: string, defaultValue: active }
hireDate: { type: date, defaultValue: NOW }
```

**Example 2: Unique constraint across multiple columns**

To make a combination of fields unique, assign an arbitrary string (such as `timeAndId`) to the corresponding fields:

```yaml
# name
machineHistory
# fields
machineId: { unique: timeAndId, type: string }
timestamp: { unique: timeAndId, type: date }
data: jsonb
```

### `getTableSchema`

Retrieves the schema definition of a given table.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>name</code></td><td>The name of the table.</td><td>string</td></tr></tbody></table>

#### Output

Returns an object containing schema details for each field, including `type`, `primaryKey`, `allowNull`, `sqlType`, `defaultValue`, `unique`, `autoIncrement`, and any referenced foreign keys.

### `deleteTable`

Deletes an entire table.

{% hint style="danger" %}

#### Irreversible action

This permanently deletes the table and all its data. You cannot undo this action.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>name</code></td><td>The name of the table to delete.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true` when deletion succeeds. If the table has an audit log table, the function removes it as well.

### `enforceUniqueField`

Retroactively enforces a UNIQUE and NOT NULL constraint on an existing field. It removes duplicate rows and rows with NULL values before applying both constraints.

{% hint style="danger" %}

#### Irreversible action

This permanently deletes duplicate and null rows. You cannot undo this action.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td></td><td>The name of the table.</td><td>string</td></tr><tr><td><code>field</code></td><td></td><td>The field to deduplicate and make unique (such as <code>barcode</code>).</td><td>string</td></tr><tr><td><code>options</code></td><td><code>keep</code></td><td>Which duplicate to keep: <code>newest</code> (latest <code>createdAt</code> or ID) or <code>oldest</code>. Default <code>newest</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true` on success. Throws an error on failure and rolls back all changes.

## Querying and filtering data

Filters can reference the currently logged-in App user, see [Referencing the current user with $USER](#referencing-the-current-user-with-usduser).

### `getTableData`

Retrieves rows from one or more tables, with options for filtering, joining, sorting, and selecting specific fields. This is the primary function for reading data.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>name</code></td><td></td><td>The name of the table, or an array of table names for a multi-table join query.</td><td>string or array</td></tr><tr><td><code>options</code></td><td><code>filter</code></td><td>The conditions rows must meet. For multi-table queries, this must include the join conditions.</td><td>array</td></tr><tr><td></td><td><code>fields</code></td><td>Selects specific columns. For multi-table queries, use dot notation (such as <code>users.name</code>).</td><td>array</td></tr><tr><td></td><td><code>order</code></td><td>The sort order specified as <code>['fieldName', 'DIRECTION']</code>, where direction is <code>ASC</code> or <code>DESC</code>.</td><td>array</td></tr><tr><td></td><td><code>limit</code></td><td>The maximum number of rows to return.</td><td>integer</td></tr><tr><td></td><td><code>offset</code></td><td>The number of rows to skip, useful for pagination.</td><td>integer</td></tr><tr><td></td><td><code>autoJoin</code></td><td>Automatically includes data from related tables for single-table queries. Default <code>true</code>.</td><td>boolean</td></tr><tr><td></td><td><code>locale</code></td><td>A locale string (such as <code>en-US</code>) to format date and time values.</td><td>string</td></tr><tr><td></td><td><code>dateStyle</code></td><td>The formatting style for dates (<code>full</code>, <code>long</code>, <code>medium</code>, <code>short</code>, or <code>hidden</code>).</td><td>string</td></tr><tr><td></td><td><code>timeStyle</code></td><td>The formatting style for times (<code>full</code>, <code>long</code>, <code>medium</code>, <code>short</code>, or <code>hidden</code>).</td><td>string</td></tr></tbody></table>

### Filtering explained

The `filter` option uses an array syntax to build precise queries.

Simple conditions are an array of three elements: `[fieldName, operator, value]`.

* `fieldName`: The column name. For `jsonb` fields, use dot notation to access nested keys (such as `specs.dimensions.width`). For multi-table queries, always prefix with the table name (such as `users.name`).
* `operator`: A comparison string, see the table below.
* `value`: The value to compare against.

Compound conditions combine conditions with `'and'` or `'or'`:

* **AND**: `[ [condition1], 'and', [condition2] ]`, both must be true.
* **OR**: `[ [condition1], 'or', [condition2] ]`, at least one must be true.

Available operators:

| Operator(s)                             | Description                                        | Example value              |
| --------------------------------------- | -------------------------------------------------- | -------------------------- |
| `=`, `==`, `eq`, `equals`, `is`         | Equals                                             | `'John'` or `100`          |
| `<>`, `!=`, `neq`, `notequals`, `isnot` | Not equals                                         | `'John'` or `100`          |
| `>`, `gt`                               | Greater than                                       | `99`                       |
| `>=`, `gte`                             | Greater than or equal to                           | `100`                      |
| `<`, `lt`                               | Less than                                          | `100`                      |
| `<=`, `lte`                             | Less than or equal to                              | `100`                      |
| `contains`                              | String field contains the value (case-insensitive) | `'oh'` (matches 'John')    |
| `notcontains`                           | String field does not contain the value            | `'Peter'`                  |
| `startswith`                            | String field starts with the value                 | `'J'`                      |
| `endswith`                              | String field ends with the value                   | `'oe'` (matches 'Doe')     |
| `between`                               | Value is between two values in an array            | `[18, 30]` or `['A', 'D']` |
| `notbetween`                            | Value is not between two values in an array        | `[18, 30]` or `['A', 'D']` |
| `in`                                    | Value is one of several possibilities in an array  | `['active', 'pending']`    |

#### Examples

**Example 1: Simple filter and field selection**

Get the `name` and `email` of all active users:

```yaml
# name
users
# options
filter: ['status', '=', 'active']
fields: ['name', 'email']
```

**Example 2: Date range filter**

Find all orders placed in January 2025:

```yaml
# name
orders
# options
filter: ['createdAt', 'between', ['2025-01-01', '2025-01-31T23:59:59Z']]
```

**Example 3: Compound 'and' filter**

Find products that are in stock and cost more than 50:

```yaml
# name
products
# options
filter: [ ['quantity', '>', 0], 'and', ['price', '>', 50] ]
```

**Example 4: Sorting and limiting**

Get the 5 most recent high-priority tickets:

```yaml
# name
tickets
# options
filter: ['priority', 'in', ['high', 'critical']]
order: ['createdAt', 'DESC']
limit: 5
```

**Example 5: Multi-table join**

Retrieve user names and post titles. The first filter condition defines the join:

```yaml
# name
- users
- posts
# options
filter: [ ['users.id', '=', 'posts.userId'] ]
fields: ['users.name', 'posts.title']
```

**Example 6: Join with a where clause**

Retrieve post titles for a specific user named Alice:

```yaml
# name
- users
- posts
# options
filter: [
  ['users.id', '=', 'posts.userId'],
  'and',
  ['users.name', '=', 'Alice']
]
fields: ['posts.title']
```

**Example 7: Join with a nested JSONB filter**

Find all orders for Alice where the shipment details JSON field has priority set to true:

```yaml
# name
- users
- orders
- shipments
# options
fields: ['users.name', 'orders.product', 'shipments.trackingNumber']
filter: [
  ['users.id', '=', 'orders.userId'],
  'and',
  ['orders.shipmentId', '=', 'shipments.id'],
  'and',
  ['users.name', '=', 'Alice'],
  'and',
  ['shipments.details.priority', '=', true]
]
```

#### Output

Returns an array of objects representing matching rows.

### `findRows`

Works like `getTableData`, but returns nothing if you do not provide a filter. Use this when the filter comes from user input (such as a search field) and an empty input should not load the entire table.

#### Parameters

The same as [`getTableData`](#gettabledata), but `filter` is effectively required.

#### Output

Returns an array of matching rows, or nothing when no filter is provided.

### `findRow`

Finds and returns the first row matching the filter. Returns nothing if you do not provide a filter.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td></td><td>The name of the table.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>filter</code></td><td>The filter conditions.</td><td>array</td></tr><tr><td></td><td><code>fields</code></td><td>An optional array of fields to return.</td><td>array</td></tr><tr><td></td><td><code>autoJoin</code></td><td>Automatically includes related data when <code>true</code>. Default <code>true</code>.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns the first matching row object, or `null` if no match is found.

### `getRow`

Retrieves a single row by its primary key.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td></td><td>The name of the table.</td><td>string</td></tr><tr><td><code>id</code></td><td></td><td>The primary key of the row.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>fields</code></td><td>An optional array of fields to return.</td><td>array</td></tr><tr><td></td><td><code>autoJoin</code></td><td>Automatically includes related data when <code>true</code>. Default <code>true</code>.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns the row object, or `null` if the ID is not found.

## Data manipulation

### `addRow`

Adds a single new row to a table.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td>The name of the table.</td><td>string</td></tr><tr><td><code>data</code></td><td>An object containing the column values to insert.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# table
users
# data
name: Jane Doe
email: jane.doe@example.com
age: 34
```

#### Output

Returns the created row as saved in the database, including the generated `id`.

### `addRows`

Adds multiple rows to a table in a single, efficient bulk operation.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td>The name of the table.</td><td>string</td></tr><tr><td><code>data</code></td><td>An array of data objects to insert.</td><td>array</td></tr></tbody></table>

#### Example

```yaml
# table
products
# data
- name: 'Thingamajig'
  price: 19.99
  stock: 100
- name: 'Widget'
  price: 25.50
  stock: 250
```

#### Output

Returns the number of rows added.

### `upsertRow`

Atomically updates or inserts a row. The function checks whether the row exists and either updates it or creates a new one. By default, the check uses the primary key (`id`). The optional `uniqueKey` parameter lets you check against another business key (such as an email) instead.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td>The name of the table.</td><td>string</td></tr><tr><td><code>data</code></td><td>The data object to upsert.</td><td>object</td></tr><tr><td><code>uniqueKey</code></td><td>An optional object specifying a unique business key for the existence check.</td><td>object</td></tr></tbody></table>

#### Examples

**Example 1: Upsert using the default primary key**

Update the user with a specific ID, or create them if they do not exist:

```yaml
# table
users
# data
id: 'a1b2c3d4-e5f6-4a3b-8c2d-1f2e3d4c5b6a'
name: Jane Smith
age: 36
```

**Example 2: Upsert using a custom unique key**

Find a user by email. If they exist, update their age; if not, create them:

```yaml
# table
users
# data
name: Jane Doe
age: 35
# uniqueKey
email: 'jane.doe@example.com'
```

#### Output

Returns the created or updated row as saved in the database. Throws an error if the upsert fails.

### `changeRow`

Changes the content of a specific row identified by its primary key.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td></td><td>The name of the table.</td><td>string</td></tr><tr><td><code>id</code></td><td></td><td>The primary key of the row to change.</td><td>string</td></tr><tr><td><code>data</code></td><td></td><td>The fields and their new values.</td><td>object</td></tr><tr><td><code>options</code></td><td><code>patch</code></td><td>Partially updates nested JSON objects instead of replacing them when <code>true</code>.</td><td>boolean</td></tr><tr><td></td><td><code>fieldDelimiter</code></td><td>Unflattens the data using the specified delimiter (such as flattening <code>settings.theme</code> to a nested object).</td><td>string</td></tr></tbody></table>

#### Example

Update a user's age and status:

```yaml
# table
users
# id
'a1b2c3d4-e5f6-4a3b-8c2d-1f2e3d4c5b6a'
# data
age: 37
status: 'active'
```

#### Output

Returns the modified row object. Throws an error if the row is not found.

### `updateRow`

Updates specific fields of an existing row, identified by the `id` inside the `data` object or by a `uniqueKey`. Fields not included in `data` remain untouched, but the database replaces JSON columns entirely with the provided value. To merge data into an existing JSON object, use `patchRow` instead.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td>The name of the table.</td><td>string</td></tr><tr><td><code>data</code></td><td>The new values. Must contain the <code>id</code> unless using <code>uniqueKey</code>.</td><td>object</td></tr><tr><td><code>uniqueKey</code></td><td>An optional object identifying the row by a business key instead of the ID. If omitted, any unique field present in <code>data</code> identifies the row automatically.</td><td>object</td></tr></tbody></table>

#### Example

Before, a row in the `settings` table:

```json
{
  "id": 1,
  "name": "Config A",
  "settings": { "theme": "dark", "notifications": true }
}
```

Call `updateRow` with:

```yaml
# table
settings
# data
id: 1
settings: {
  notifications: false,
  timezone: UTC
}
```

After:

```json
{
  "id": 1,
  "name": "Config A",
  "settings": { "notifications": false, "timezone": "UTC" }
}
```

The `name` field stayed untouched, but the `theme` key in the JSON is gone.

#### Output

Returns the updated row object. Throws an error if the row is not found.

### `patchRow`

Patches a row with new data by merging nested JSON objects instead of replacing them. Original JSON keys not included in the patch are preserved.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td>The name of the table.</td><td>string</td></tr><tr><td><code>data</code></td><td>The new values. Must contain the <code>id</code> unless using <code>uniqueKey</code>.</td><td>object</td></tr><tr><td><code>uniqueKey</code></td><td>An optional object identifying the row by a business key instead of the ID. If omitted, any unique field present in <code>data</code> identifies the row automatically.</td><td>object</td></tr></tbody></table>

#### Example

Before, a row in the `settings` table:

```json
{
  "id": 1,
  "name": "Config A",
  "settings": { "theme": "dark", "notifications": true }
}
```

Call `patchRow` with:

```yaml
# table
settings
# data
id: 1
settings: {
  notifications: false,
  timezone: UTC
}
```

After:

```json
{
  "id": 1,
  "name": "Config A",
  "settings": { "theme": "dark", "notifications": false, "timezone": "UTC" }
}
```

The original `theme` key is preserved and the new data is merged in.

#### Output

Returns the patched row object. Throws an error if the row is not found.

### `deleteRow`

Deletes a single row from a table, identified by its primary key.

{% hint style="danger" %}

#### Irreversible action

This permanently deletes the row. You cannot undo this action.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td>The name of the table.</td><td>string</td></tr><tr><td><code>id</code></td><td>The primary key of the row to delete.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# table
users
# id
'a1b2c3d4-e5f6-4a3b-8c2d-1f2e3d4c5b6a'
```

#### Output

Returns `true` if the row is deleted, or `false` if no row with that ID exists.

### `clearTable`

Deletes all rows from a table, leaving the table structure intact.

{% hint style="danger" %}

#### Irreversible action

This permanently deletes all data in the table. You cannot undo this action.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>name</code></td><td></td><td>The name of the table to clear.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>nullifyLinkedRecords</code></td><td>Sets foreign keys in other tables pointing to this table to <code>NULL</code> before clearing when <code>true</code>. Default <code>false</code>.</td><td>boolean</td></tr></tbody></table>

#### Example

```yaml
# name
logs
```

#### Output

Returns `true` on success.

## Relationships and associations

These functions define logical connections between tables to create a relational data model. Relationships ensure data integrity and enable cross-table queries. The workflow has three steps:

1. **Define tables**: Create your tables using `defineTable`.
2. **Define the relationship**: Use one of the association functions to declare how the tables connect.
3. **Link records**: Use the foreign key fields created in step 2 to connect specific rows. For many-to-many relationships, use `associateRow`.

### `optionallyHasOne`

Creates a one-to-many relationship where the child record can exist without a parent. This adds a nullable foreign key column to the child table. In short: a child has zero or one parent, a parent may have many children.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>childTable</code></td><td>The table that receives the foreign key (such as <code>posts</code>).</td><td>string</td></tr><tr><td><code>parentTable</code></td><td>The table being referenced (such as <code>users</code>).</td><td>string</td></tr><tr><td><code>role</code></td><td>An optional PascalCase string (such as <code>Owner</code>) to create a distinct relationship.</td><td>string</td></tr></tbody></table>

### `mandatorilyHasOne`

Creates a one-to-many relationship where the child record cannot exist without a parent. This adds a non-nullable foreign key column to the child table. In short: a child must have exactly one parent, a parent may have many children.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>childTable</code></td><td>The table that receives the foreign key (such as <code>employees</code>).</td><td>string</td></tr><tr><td><code>parentTable</code></td><td>The table being referenced (such as <code>companies</code>).</td><td>string</td></tr><tr><td><code>role</code></td><td>An optional PascalCase string (such as <code>Manager</code>) to create a distinct relationship.</td><td>string</td></tr></tbody></table>

### `optionallyHasMany`

Creates a many-to-many relationship between two tables. This automatically generates a hidden junction table to manage the associations. In short: a child can have many parents, a parent can have many children.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>childTable</code></td><td>The first table in the relationship.</td><td>string</td></tr><tr><td><code>parentTable</code></td><td>The second table in the relationship.</td><td>string</td></tr></tbody></table>

### `associateRow`

Links existing records. Use this to create links for a many-to-many relationship after defining it.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>sourceTable</code></td><td>The name of the source table.</td><td>string</td></tr><tr><td><code>sourceId</code></td><td>The ID of the row in the source table.</td><td>string</td></tr><tr><td><code>targetTable</code></td><td>The name of the target table.</td><td>string</td></tr><tr><td><code>targetId</code></td><td>The ID or an array of IDs of the row(s) in the target table.</td><td>string or array</td></tr></tbody></table>

#### Output

Returns `true` when the association succeeds.

### Relationship strategies and examples

This section guides you through choosing and implementing relationships.

#### One-to-many (mandatory)

The most common relationship. Use it when a child record requires a parent. Example: An employee must belong to a company.

{% stepper %}
{% step %}

#### Define tables

Create the `companies` and `employees` tables.

```yaml
# (call defineTable)
# name
companies
# fields
name: string

# (call defineTable)
# name
employees
# fields
firstName: string
lastName: string
```

{% endstep %}

{% step %}

#### Define the relationship

Declare that an employee mandatorily has one company.

```yaml
# (call mandatorilyHasOne)
# childTable
employees
# parentTable
companies
```

{% hint style="info" %}
This adds a non-nullable `companyId` foreign key column to the `employees` table.
{% endhint %}
{% endstep %}

{% step %}

#### Link records

Because `companyId` is mandatory, provide it when creating a new employee record.

```yaml
# (call addRow)
# table
employees
# data
firstName: Ada
lastName: Lovelace
companyId: 'a1b2c3d4-e5f6-4a3b-8c2d-1f2e3d4c5b6a'
```

{% endstep %}
{% endstepper %}

#### One-to-many (optional)

Use this when the link between child and parent is optional. The child can be created first and linked later. Example: A blog post can optionally be assigned to a category.

{% stepper %}
{% step %}

#### Define tables

```yaml
# (call defineTable)
# name
posts
# fields
title: string
content: text

# (call defineTable)
# name
categories
# fields
name: string
```

{% endstep %}

{% step %}

#### Define the relationship

Declare that a post optionally has one category.

```yaml
# (call optionallyHasOne)
# childTable
posts
# parentTable
categories
```

{% hint style="info" %}
This adds a nullable `categoryId` foreign key column to the `posts` table.
{% endhint %}
{% endstep %}

{% step %}

#### Link records

Create a post without a category, and link it later by patching the record.

```yaml
# (call addRow to create the post initially)
# table
posts
# data
title: 'My First Post'
content: '...'

# (call patchRow later to link it to a category)
# table
posts
# data
id: 'f1e2d3c4-b5a6-4a3b-8c2d-1f2e3d4c5b6a'
categoryId: 'c1b2a3d4-e5f6-4a3b-8c2d-1f2e3d4c5b6a'
```

{% endstep %}
{% endstepper %}

#### Many-to-many

Use this when records in two tables can have multiple links to each other. Example: An order can contain many products, and a product can be part of many orders.

{% stepper %}
{% step %}

#### Define tables

```yaml
# (call defineTable)
# name
orders
# fields
orderDate: date

# (call defineTable)
# name
products
# fields
name: string
price: number
```

{% endstep %}

{% step %}

#### Define the relationship

Declare the many-to-many relationship between orders and products.

```yaml
# (call optionallyHasMany)
# childTable
orders
# parentTable
products
```

{% hint style="info" %}
This automatically creates a hidden junction table (such as `__orders2products`) storing the links between order IDs and product IDs.
{% endhint %}
{% endstep %}

{% step %}

#### Link records

Connect the records with `associateRow`. Link one order to multiple products by providing an array of product IDs.

```yaml
# (call associateRow)
# sourceTable
orders
# sourceId
'o1d2e3r4-b5a6-4a3b-8c2d-1f2e3d4c5b6a'
# targetTable
products
# targetId
- 'p1r2o3d4-b5a6-4a3b-8c2d-1f2e3d4c5b6a'
- 'p5r6o7d8-b5a6-4a3b-8c2d-1f2e3d4c5b6a'
```

{% endstep %}
{% endstepper %}

#### Advanced: multiple relationships with roles

Use the `role` parameter to define multiple distinct relationships between the same two tables (such as a document with both an owner and an editor from the `users` table).

{% stepper %}
{% step %}

#### Define tables

```yaml
# (call defineTable)
# name
users
# fields
name: string

# (call defineTable)
# name
documents
# fields
title: string
```

{% endstep %}

{% step %}

#### Define the relationships with roles

Create two distinct one-to-many relationships, specifying a role for each.

```yaml
# (call optionallyHasOne for the owner)
# childTable
documents
# parentTable
users
# role
Owner

# (call optionallyHasOne for the editor)
# childTable
documents
# parentTable
users
# role
Editor
```

{% hint style="info" %}
This adds two separate foreign keys to the `documents` table: `ownerId` and `editorId`. The role name directly determines the name of the foreign key.
{% endhint %}
{% endstep %}

{% step %}

#### Link records

When creating a document, provide IDs for both the owner and the editor using the specific foreign key fields.

```yaml
# (call addRow)
# table
documents
# data
title: 'Q4 Financial Report'
ownerId: 'u1s2e3r4-b5a6-4a3b-8c2d-1f2e3d4c5b6a'
editorId: 'u5s6e7r8-b5a6-4a3b-8c2d-1f2e3d4c5b6a'
```

{% endstep %}
{% endstepper %}

## Audit logging

The relational database connector (`RelationalDatabase`) features a built-in audit logging system that creates a secure, detailed, and queryable trail of all data changes. It tracks what changed, when, and who changed it. It automatically calculates the differences (diff) between old and new values for updates, and stores full snapshots for creations and deletions.

{% hint style="warning" %}

#### Deprecation notice

The `trackHistory` option in `defineTable` and the `getHistoricalData` function are deprecated as of February 2025. Use `auditLog` and `getAuditLog` instead.
{% endhint %}

### Enabling audit logs

Set the `auditLog` option to `true` when defining the table schema:

```yaml
# name
orders
# fields
orderNumber: string
status: string
total: number
# options
auditLog: true
```

The database automatically creates a parallel table (such as `ordersAuditLog`) recording all CREATE, UPDATE, and DELETE actions on the main table.

### Tracking the actor

To record who made a change, all data manipulation functions accept an optional `actorId` within their options. In an App, bind this to the authenticated user via the [`$USER` variable](#referencing-the-current-user-with-usduser) or their user ID.

```yaml
# table
orders
# data
id: 'order-123'
status: 'shipped'
# options
actorId: 'admin-alice'
```

### `getAuditLog`

Retrieves and filters the recorded history, including natural language time parsing and field-level tracking.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td></td><td>The name of the table to query.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>id</code></td><td>Filters logs for a specific record's primary key.</td><td>string</td></tr><tr><td></td><td><code>actorId</code></td><td>Filters logs by the user who made the change.</td><td>string</td></tr><tr><td></td><td><code>action</code></td><td>Filters by action type (<code>CREATE</code>, <code>UPDATE</code>, or <code>DELETE</code>).</td><td>string</td></tr><tr><td></td><td><code>changedField</code></td><td>Returns only logs where a specific field was modified.</td><td>string</td></tr><tr><td></td><td><code>start</code></td><td>The earliest time to include, supporting natural language (such as <code>yesterday</code> or <code>-1h</code>).</td><td>string</td></tr><tr><td></td><td><code>stop</code></td><td>The latest time to include. Default <code>now</code>.</td><td>string</td></tr></tbody></table>

#### Examples

**Example 1: View all changes to a specific record**

```yaml
# table
orders
# options
id: 'order-999'
```

**Example 2: Track specific field modifications**

Find out who changed the `status` field of an order, and when:

```yaml
# table
orders
# options
id: 'order-999'
changedField: status
```

**Example 3: Monitor user activity**

See all deletions performed by a specific admin in the last 24 hours:

```yaml
# table
products
# options
action: DELETE
actorId: admin-alice
start: -24h
```

#### Output

An array of log entries, ordered from newest to oldest. The `diff` object varies by action:

**CREATE**: There is no old state; `new` contains the complete inserted record.

```json
{
  "action": "CREATE",
  "actorId": "admin-alice",
  "diff": {
    "old": null,
    "new": { "id": "order-123", "status": "pending", "total": 150.00 }
  },
  "createdAt": "2025-08-20T10:00:00.000Z"
}
```

**UPDATE**: The `diff` contains only the fields that actually changed, with their old and new values.

```json
{
  "action": "UPDATE",
  "actorId": "admin-alice",
  "diff": {
    "status": {
      "old": "pending",
      "new": "shipped"
    }
  },
  "createdAt": "2025-08-21T14:30:00.000Z"
}
```

**DELETE**: There is no new state; `old` contains the final snapshot of the record.

```json
{
  "action": "DELETE",
  "actorId": "admin-alice",
  "diff": {
    "old": { "id": "order-123", "status": "shipped", "total": 150.00 },
    "new": null
  },
  "createdAt": "2025-08-25T09:15:00.000Z"
}
```

## Auto-schema functions

These functions create and alter tables on the fly. Use them for rapid prototyping or unpredictable data structures.

### `autoUpsertRow`

Upserts a row. If the table or columns do not exist, the function creates them automatically based on the provided data.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td>The name of the table.</td><td>string</td></tr><tr><td><code>data</code></td><td>The data object to upsert.</td><td>object</td></tr><tr><td><code>uniqueKey</code></td><td>An optional unique key for the existence check.</td><td>object</td></tr></tbody></table>

#### Output

Returns `true` on success, or `false` if it fails. Errors are logged but not thrown.

### `autoAddRows`

Bulk-inserts data. Like `autoUpsertRow`, it creates or alters the table schema as needed based on the first data object in the array.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>table</code></td><td>The name of the table.</td><td>string</td></tr><tr><td><code>data</code></td><td>An array of data objects to insert. The schema is derived from the first object.</td><td>array</td></tr><tr><td><code>uniqueKey</code></td><td>An optional unique key for the existence check.</td><td>object</td></tr></tbody></table>

#### Output

Returns `true` on success, or `false` if it fails. Errors are logged but not thrown.

## Raw SQL and templates

### `executeSql`

Executes a raw SQL statement with template variable substitution. Placeholders such as `{{customer.id}}` are safely replaced with values from the `variables` object. For `SELECT` statements, the query returns an array of row objects.

{% hint style="danger" %}

#### Irreversible action

Raw SQL can modify or delete database schemas and records. Run custom scripts with caution.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>template</code></td><td></td><td>The SQL string containing <code>{{double.curly.braces}}</code> placeholders.</td><td>string</td></tr><tr><td><code>variables</code></td><td></td><td>The object containing the data for the placeholders. Nested values are addressed with dot notation.</td><td>object</td></tr><tr><td><code>options</code></td><td><code>type</code></td><td>Forces a specific query type (such as <code>SELECT</code>, <code>UPDATE</code>, or <code>INSERT</code>).</td><td>string</td></tr><tr><td></td><td><code>locale</code></td><td>Formats dates and times in the result using local representation (such as <code>de-DE</code>).</td><td>string</td></tr><tr><td></td><td><code>dateStyle</code></td><td>The formatting style for dates (<code>full</code>, <code>long</code>, <code>medium</code>, or <code>short</code>).</td><td>string</td></tr><tr><td></td><td><code>timeStyle</code></td><td>The formatting style for times (<code>full</code>, <code>long</code>, <code>medium</code>, or <code>short</code>).</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# template
SELECT name, email FROM users WHERE "companyId" = {{company.id}} AND age > {{minAge}}
# variables
company: { id: 'a1b2c3d4' }
minAge: 30
```

#### Output

Returns the result of the query. For `SELECT` statements, this is an array of row objects.

### `fillTemplate`

Fills a template string with data from the first record matching a given condition per table. Placeholders use double curly braces such as `{{table.field}}` or nested keys such as `{{table.jsonField.nestedKey}}`. If you provide a `locale`, the function formats ISO date-time values automatically. Unresolved placeholders are removed from the result.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>template</code></td><td></td><td>The template string containing placeholders.</td><td>string</td></tr><tr><td><code>condition</code></td><td></td><td>An object mapping table names to their filter conditions.</td><td>object</td></tr><tr><td><code>options</code></td><td><code>locale</code></td><td>The locale for date and time formatting (such as <code>en-US</code> or <code>de-DE</code>).</td><td>string</td></tr><tr><td></td><td><code>dateStyle</code></td><td>The formatting style for dates (<code>full</code>, <code>long</code>, <code>medium</code>, or <code>short</code>). Default <code>medium</code>.</td><td>string</td></tr><tr><td></td><td><code>timeStyle</code></td><td>The formatting style for times (<code>full</code>, <code>long</code>, <code>medium</code>, or <code>short</code>). Default <code>medium</code>.</td><td>string</td></tr></tbody></table>

#### Example

Create a notification string for a specific user and their latest order:

```yaml
# template
"Hello {{users.name}}! Your order #{{orders.orderNumber}} will ship on {{orders.details.shippingDate}}."
# condition
users: ['id', '=', 'user-123']
orders: ['userId', '=', 'user-123']
# options
locale: en-GB
dateStyle: long
```

Result (example): "Hello Jane Doe! Your order #98765 will ship on 18 August 2025."

#### Output

Returns the template string with all resolved placeholders.

## Change notifications

### `onChange`

Registers a callback executed whenever the specified table changes (insert, update, or delete).

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>name</code></td><td>The name of the table to subscribe to.</td><td>string</td></tr><tr><td><code>handler</code></td><td>The callback evaluated on every change to the table.</td><td>callback</td></tr></tbody></table>

#### Output

Returns `'subscribed'` to confirm registration.

## Deprecated functions

The following functions are maintained for backward compatibility. Use their recommended replacements in new flows.

| Deprecated function                       | Use instead                     |
| ----------------------------------------- | ------------------------------- |
| `getHistoricalData` (with `trackHistory`) | `getAuditLog` (with `auditLog`) |
| `findOne`                                 | `findRow`                       |

## Tips and tricks

### Referencing the current user with $USER

The `$USER` variable references the authenticated user of your App. Define the username as a unique key (type `uniquestring`) when creating the table to allow [`upsertRow`](#upsertrow) to update and insert rows based on that unique key.

<div align="center"><figure><img src="/files/xq68Hmu4zmtA2qCMSCMg" alt=""><figcaption><p>$USER in combination with the upsertRow function</p></figcaption></figure></div>


# Timeseries database

The timeseries database connector is a specialized client for InfluxDB. It stores high-frequency data where the recording time is as important as the value itself, such as sensor readings, machine performance metrics, or energy consumption.

{% hint style="info" %}

#### Intelligent downsampling and native multi-fields

The connector supports downsampling. It retains high-resolution raw data for recent events while automatically aggregating older data into lower-resolution buckets to optimize storage.

It also natively supports multi-field telemetry. When you log entire objects (such as `{ cycle_time: 4.2, yield: 150 }`), the database automatically fans them out into individual queryable fields and reconstructs the object on the fly when you read it back.
{% endhint %}

## Quick start: the internal instance

Heisenware provides a pre-initialized InfluxDB instance called `internal-influx`. It is globally available and ready for use. Pick functions from inside `internal-influx` to make use of it.

<figure><img src="/files/6aLTIfGrtHTCnH61Q59D" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}

#### Direct data recording with the recorder

The [recorder](/app-builder/build-backend/extension-nodes/recorder) extension node provides the fastest way to log data. Click the `+` icon on any function output or modifier and select the recorder. By default, the node logs data directly into the `internal-influx` instance without extra function blocks in your flow.
{% endhint %}

## Connecting an external database

To connect an external InfluxDB instance, use the [`create`](#create) function:

* **Cloud or public database**: Connect directly if your InfluxDB server is accessible via the internet.
* **Local database (via Agent)**: If your InfluxDB sits inside a private network, deploy an [Agent](/app-builder/build-backend/agents) in that network first and create the database instance within that Agent.

{% hint style="info" %}
The functions for writing and querying data remain identical whether you use the managed `internal-influx` or a custom connection.
{% endhint %}

## Downsampling pipeline

The downsampling pipeline stores data efficiently, letting you write high-frequency data (such as sensor readings every second) without running out of storage or slowing down queries over long time ranges.

#### Hot and cold data

The system categorizes data by age:

* **Hot data (recent)**: Requires high detail for real-time monitoring (such as detecting short temperature spikes).
* **Cold data (historical)**: Requires trend visibility rather than microsecond detail (such as analyzing average monthly temperatures).

The system automatically moves data through buckets as it ages, reducing resolution to optimize storage while maintaining statistical accuracy.

#### Pipeline structure

Data flows automatically through a series of stages. Write data only to the start of the pipeline.

You never see the `+` buckets in the software. They are the internal stages of this pipeline. What you select instead, for example as the recording type of a [recorder](/app-builder/build-backend/extension-nodes/recorder), is either a fixed retention (`H`, `D`, `W`, `M`, or `Y`, keeping raw data for 1 hour up to 1 year, matching the letter) or `DS` (downsampled), which feeds this pipeline for long-term storage without a fixed retention.

![](/files/uhScyfsMQAruKwAawv2p)

<table><thead><tr><th width="102.66650390625">Bucket</th><th width="184.4444580078125">Resolution</th><th width="130.9261474609375">Retention</th><th>Typical use</th></tr></thead><tbody><tr><td><code>H+</code></td><td>Raw (every point)</td><td>1 day</td><td>Real-time monitoring, debugging recent events</td></tr><tr><td><code>D+</code></td><td>5 minutes</td><td>1 week</td><td>Zooming into last week's performance</td></tr><tr><td><code>W+</code></td><td>1 hour</td><td>1 week</td><td>Weekly trends and patterns</td></tr><tr><td><code>M+</code></td><td>1 day</td><td>1 month</td><td>Monthly analysis and seasonal trends</td></tr><tr><td><code>Y+</code></td><td>1 week</td><td>1 year</td><td>Yearly trends and seasonal patterns</td></tr><tr><td><code>F+</code></td><td>1 month</td><td>Forever</td><td>Long-term historical archiving</td></tr></tbody></table>

#### How writing works

Write operations send data to the raw (`H+`) bucket automatically. Background tasks then process the data. For example, every 5 minutes a task extracts raw data from `H+`, calculates the mean, minimum, maximum, and count, and saves a summary point to the `D+` bucket.

#### How reading works (smart stitching)

You do not need to specify a bucket when reading data. Provide a time range and `readDownsampled` routes the query:

1. It evaluates the requested `start` and `stop` times.
2. It selects the highest-resolution bucket available for that period.
3. It stitches the data together if the request spans retention boundaries.

For example, if you query the last 2 days, the function returns the last 24 hours from the raw (`H+`) bucket and the preceding 24 hours from the 5-minute (`D+`) bucket.

#### Configuration examples

* **Real-time debugging**: Pulls from the raw (`H+`) bucket to view the last 15 minutes.

  ```yaml
  # (readDownsampled)
  # options
  start: "-15m"
  tail: 100
  ```
* **Monthly reporting**: Pulls from the hourly (`W+`) or daily (`M+`) buckets to visualize trends over the last 30 days.

  ```yaml
  # (readDownsampled)
  # options
  start: "-30d"
  limit: 1000
  ```
* **Stitched view**: Returns the last 50 data points regardless of age, automatically querying older buckets if needed.

  ```yaml
  # (readDownsampled)
  # options
  tail: 50
  ```

#### Aggregated fields

During downsampling, the pipeline preserves four key statistics for each window:

* `mean`: The average value.
* `max`: The highest value.
* `min`: The lowest value.
* `count`: The total number of raw data points in the window.

## Connection

### `create`

Creates an InfluxDB client instance.

{% hint style="info" %}
Skip this step for `internal-influx`. It is already instantiated for you.
{% endhint %}

#### Parameters

<table><thead><tr><th width="114.8148193359375">Input</th><th width="198.703857421875">Key</th><th width="292.66650390625">Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td></td><td>The URL of the InfluxDB instance (such as <code>http://localhost:8086</code>).</td><td>string</td></tr><tr><td><code>token</code></td><td></td><td>The authentication token with permissions for the target organization and buckets.</td><td>string</td></tr><tr><td><code>org</code></td><td></td><td>The name of the organization in InfluxDB.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>flushInterval</code></td><td>The interval in milliseconds to flush buffered writes. Default 5000.</td><td>integer</td></tr><tr><td></td><td><code>batchSize</code></td><td>The number of points to buffer before writing. Default 1000.</td><td>integer</td></tr><tr><td></td><td><code>downsamplingPipeline</code></td><td>Overrides the default downsampling stages.</td><td>array</td></tr></tbody></table>

{% hint style="info" %}
Right-click the `token` input and mark it as a secret to mask it.
{% endhint %}

#### Output

Returns the name of the created instance.

### `delete` (instance)

Removes the timeseries database client instance and its connection configuration. Not to be confused with [`delete` (data)](#delete-data), which deletes measurement data.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration. To communicate with the database again, you must create a new instance.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

## Writing data

### `writePoint`

Writes a single data point to a specific bucket and measurement.

When you pass an object as data, the engine fans it out into native InfluxDB fields, allowing fast analytics on individual properties later. If a measurement historically used stringified JSON, the database continues using it to preserve existing dashboards.

#### Parameters

<table><thead><tr><th width="123.14794921875">Input</th><th width="506.4072265625">Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>bucket</code></td><td>The name of the bucket to write to.</td><td>string</td></tr><tr><td><code>measurement</code></td><td>The name of the measurement (such as <code>temperature</code> or <code>production_line</code>).</td><td>string</td></tr><tr><td><code>data</code></td><td>The value to record. Accepts a number, string, boolean, or object (such as <code>{ temp: 45, status: "ok" }</code>).</td><td>any</td></tr><tr><td><code>tags</code></td><td>Optional key-value pairs to tag the data. To force the object storage behavior, add <code>objectStorageType: 'fields'</code> or <code>objectStorageType: 'json'</code>. The database strips this control flag before saving.</td><td>object</td></tr></tbody></table>

<div align="left"><figure><img src="/files/qCxdnS3Wz1SB8Q09IdPH" alt="" width="375"><figcaption><p>Measurement vs. tags vs. fields</p></figcaption></figure></div>

#### Example

```yaml
# bucket
D
# measurement
production_line
# data
cycle_time: 4.2
yield: 150
# tags
location: warehouse
line_id: A1
objectStorageType: fields
```

#### Output

Returns `true` when the point is accepted for buffered writing, including when the data type is invalid (the connector then skips the write and logs a warning). Write failures surface in the logs, not as errors.

{% hint style="info" %}

#### Internal bucket names

When using the internal database, bucket names indicate retention: `F` (forever), `Y` (year), `M` (month), `W` (week), `D` (day), `H` (hour).
{% endhint %}

### `writePoints`

Writes multiple data points to a specific bucket and measurement. This is more efficient than calling `writePoint` in a loop.

#### Parameters

<table><thead><tr><th width="128.7037353515625">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>bucket</code></td><td>The name of the bucket.</td><td>string</td></tr><tr><td><code>measurement</code></td><td>The name of the measurement.</td><td>string</td></tr><tr><td><code>data</code></td><td>An array of values or objects to record.</td><td>array</td></tr><tr><td><code>tags</code></td><td>Optional tags. If specified as an array, the length must match the <code>data</code> array (one tag object per point). If specified as a single object, the tags apply to all points.</td><td>any</td></tr></tbody></table>

#### Example

```yaml
# bucket
D
# measurement
vibration
# data
- 0.5
- 0.6
- 0.4
- 0.8
```

#### Output

Returns `true` when the points are accepted for buffered writing. Throws an error if `data` is not an array or the length of a tags array does not match the data array. Write failures surface in the logs, not as errors.

### `writeDownsampled`

Writes numeric data or multi-field objects to the high-frequency bucket (`H+`) for automatic downsampling.

When you pass an object containing both numbers and strings (such as `{ speed: 120, status: "running" }`), the system retains the full object in the raw `H+` bucket for debugging, but only aggregates numeric fields into long-term historical buckets. The pipeline drops non-numeric fields (such as strings and booleans) during downsampling and logs a warning.

#### Parameters

<table><thead><tr><th width="139.8148193359375">Input</th><th width="489.4813232421875">Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>measurement</code></td><td>The name of the measurement.</td><td>string</td></tr><tr><td><code>data</code></td><td>The numeric value, object, or array to store.</td><td>any</td></tr><tr><td><code>tags</code></td><td>Optional tags to associate with the data.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# measurement
extruder_metrics
# data
speed: 230.5
temperature: 180.2
status: heating
# tags
machine: m1
```

#### Output

Returns `true` when the data is accepted for buffered writing, including when no numeric fields remain after filtering (the connector then logs a warning).

## Reading data

### `read`

Reads timeseries data from a specific bucket and measurement, with options for filtering by time, isolating fields, limiting results, and aggregating data.

When you query a measurement containing multiple fields and do not specify a target field, the engine automatically pivots the data and reconstructs the original object.

#### Parameters

<table><thead><tr><th width="133.33349609375">Input</th><th width="148.7037353515625">Key</th><th width="377.036865234375">Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>bucket</code></td><td></td><td>The name of the bucket to query.</td><td>string</td></tr><tr><td><code>measurement</code></td><td></td><td>The name of the measurement.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>field</code></td><td>The specific field to isolate (such as <code>cycle_time</code>). If omitted, the function returns all fields as an object.</td><td>string</td></tr><tr><td></td><td><code>start</code></td><td>The earliest time to include (such as <code>-12h</code>, <code>-7d</code>, or <code>2025-01-01T00:00:00Z</code>). Default <code>-1y</code>.</td><td>string</td></tr><tr><td></td><td><code>stop</code></td><td>The latest time to include. Default <code>now()</code>.</td><td>string</td></tr><tr><td></td><td><code>limit</code></td><td>Limits the result to the first n data points.</td><td>integer</td></tr><tr><td></td><td><code>tail</code></td><td>Limits the result to the last n data points.</td><td>integer</td></tr><tr><td></td><td><code>every</code></td><td>The duration of time windows for aggregation (such as <code>15m</code>).</td><td>string</td></tr><tr><td></td><td><code>func</code></td><td>The aggregation function applied per window (such as <code>mean</code>, <code>sum</code>, <code>count</code>, or <code>last</code>). Default <code>mean</code>.</td><td>string</td></tr><tr><td></td><td><code>tags</code></td><td>An object of tags to filter by.</td><td>object</td></tr><tr><td></td><td><code>difference</code></td><td>Calculates differences between readings when set to <code>true</code>. Set to <code>nonNegative</code> to ignore counter resets. Default <code>false</code>.</td><td>any</td></tr><tr><td></td><td><code>fillPrevious</code></td><td>Carries the last known value forward into empty time windows when set to <code>true</code>. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>cumulativeSum</code></td><td>Keeps a running total across the selected time range when set to <code>true</code>. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>derivativeUnit</code></td><td>Calculates the rate of change per given unit (such as <code>1m</code> for per-minute rates).</td><td>string</td></tr></tbody></table>

<details>

<summary>Understanding aggregation</summary>

Timeseries databases often contain thousands of individual points. To visualize this data effectively, group the points into larger time windows and summarize them. Two parameters control this:

* `every`: The size of the time window (such as `1h`, `15m`, or `1d`).
* `func`: The calculation applied to the points within each window.

#### Available functions

| Function | Description                          | Typical use case                                                    |
| -------- | ------------------------------------ | ------------------------------------------------------------------- |
| `mean`   | Calculates the average value.        | Smoothing noisy sensor data (such as average temperature per hour). |
| `median` | Finds the middle value.              | Finding the typical value while ignoring extreme outliers.          |
| `min`    | Finds the lowest value.              | Detecting the coldest temperature or lowest battery level.          |
| `max`    | Finds the highest value.             | Detecting peak power usage or maximum pressure.                     |
| `sum`    | Adds up all values.                  | Calculating total energy consumption or total volume flowed.        |
| `count`  | Counts the number of data points.    | Counting machine cycles or error logs.                              |
| `last`   | Takes the last value in the window.  | The final state of a system at the end of each period.              |
| `first`  | Takes the first value in the window. | The starting state of a system at the beginning of each period.     |

</details>

#### Examples

**Example 1: Smoothing noisy sensor data (averages)**

An analog sensor sends data every second. Group the data into time windows and calculate the mean to smooth the trend over the last 12 hours:

```yaml
# bucket
D
# measurement
extruder_temp
# options
start: -12h
every: 5m
func: mean
```

**Example 2: Peak detection and shift highs**

Find the maximum value reached per reporting period over the last 30 days:

```yaml
# bucket
D
# measurement
motor_temperature
# options
start: -30d
every: 1d
func: max
```

**Example 3: Counting incidents or machine faults**

Count how many faults or failed inspections occurred per time window for the current shift:

```yaml
# bucket
D
# measurement
qa_failures
# options
start: -8h
every: 1h
func: count
```

**Example 4: The resetting machine counter (pieces produced)**

A PLC part counter resets to 0 at shift end. Use `difference: nonNegative` to calculate pieces produced between readings while ignoring the negative drop at reset:

```yaml
# bucket
D
# measurement
packaging_line
# options
field: piece_counter
start: -24h
every: 1h
func: sum
difference: nonNegative
```

**Example 5: Event-driven machine states (sparse data)**

A machine only sends data on state changes, leaving gaps in the timeline. Use `fillPrevious: true` to carry the last known state forward into empty windows:

```yaml
# bucket
D
# measurement
cnc_machine_1
# options
field: status_code
start: -8h
every: 1m
func: last
fillPrevious: true
```

**Example 6: Cumulative running totals (energy or water usage)**

Show the running total of energy consumed in the last 12 hours:

```yaml
# bucket
D
# measurement
main_power_meter
# options
field: interval_kwh
start: -12h
every: 15m
func: sum
cumulativeSum: true
```

**Example 7: Rate of change (derivatives)**

Calculate the minute-by-minute drain rate of a chemical tank:

```yaml
# bucket
D
# measurement
chemical_tank_A
# options
field: volume_liters
start: -1h
derivativeUnit: 1m
```

**Example 8: Isolating metrics from multi-field payloads**

Show the maximum vibration recorded every 5 minutes from a multi-field payload:

```yaml
# bucket
D
# measurement
robot_arm_2
# options
field: vibration
start: -24h
every: 5m
func: max
```

#### Output

Returns an array of objects, each containing a `date` (ISO timestamp) and a `value` (a primitive value or a reconstructed object).

```json
[
  { "date": "2025-10-27T10:00:00Z", "value": { "cycle_time": 4.2, "yield": 150 } },
  { "date": "2025-10-27T10:15:00Z", "value": { "cycle_time": 4.1, "yield": 152 } }
]
```

### `readDownsampled`

Reads downsampled data by automatically stitching together details across downsampling buckets (raw `H+` for recent data, aggregated `D+`/`W+`/`M+`/`Y+` for older data).

#### Parameters

<table><thead><tr><th width="132.4072265625">Input</th><th width="93.1480712890625">Key</th><th width="400.70361328125">Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>measurement</code></td><td></td><td>The name of the measurement.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>field</code></td><td>The specific field to extract. Default <code>value</code>.</td><td>string</td></tr><tr><td></td><td><code>aggFunc</code></td><td>The statistic returned as the main value (such as <code>mean</code> or <code>max</code>). Default <code>mean</code>.</td><td>string</td></tr><tr><td></td><td><code>start</code></td><td>The earliest time to include. Default <code>-1y</code>.</td><td>string</td></tr><tr><td></td><td><code>stop</code></td><td>The latest time to include. Default <code>now()</code>.</td><td>string</td></tr><tr><td></td><td><code>limit</code></td><td>Limits the result to the first n points.</td><td>integer</td></tr><tr><td></td><td><code>tail</code></td><td>Limits the result to the last n points.</td><td>integer</td></tr><tr><td></td><td><code>tags</code></td><td>Filters by tags.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# measurement
production_line
# options
start: -30d
field: cycle_time
aggFunc: max
tags:
  line_id: A1
```

#### Output

Returns an array of objects containing statistics (`mean`, `min`, `max`, `count`) per time point. The requested `aggFunc` maps to the main `value` key.

```json
[
  {
    "date": "2025-10-01T00:00:00Z",
    "mean": 4.5,
    "min": 4.1,
    "max": 5.2,
    "count": 60,
    "value": 5.2,
    "raw": false
  }
]
```

### `query`

Executes a raw Flux query string for complex database operations.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>flux</code></td><td>The raw Flux query string.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# flux
from(bucket:"my-bucket") |> range(start: -1h) |> filter(fn: (r) => r._measurement == "cpu")
```

#### Output

Returns the raw query result rows from InfluxDB.

## Live data and caching

### `subscribeToChange`

Registers a callback executed whenever new data is written to a measurement.

#### Parameters

<table><thead><tr><th width="128.7037353515625">Input</th><th width="162.592529296875">Key</th><th width="359.7037353515625">Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>measurement</code></td><td></td><td>The name of the measurement to watch.</td><td>string</td></tr><tr><td><code>handler</code></td><td></td><td>The callback evaluated on every write. Receives an object containing the measurement name, plus the written data and tags when <code>includeData</code> is enabled.</td><td>callback</td></tr><tr><td><code>options</code></td><td><code>samplingInterval</code></td><td>Guarantees the handler fires at most once every X milliseconds. Default 0.</td><td>integer</td></tr><tr><td></td><td><code>includeData</code></td><td>Includes the written data and tags in the payload when set to <code>true</code>. Default false.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns a unique handler ID string. Use this ID with `unsubscribeFromChange` to remove the listener.

#### Example

```yaml
# measurement
production_line
# handler
<callback>
# options
samplingInterval: 1000
includeData: true
```

### `unsubscribeFromChange`

Unregisters change handlers. Call it without parameters to remove all handlers across all measurements.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>measurement</code></td><td>An optional measurement to unsubscribe from.</td><td>string</td></tr><tr><td><code>handlerId</code></td><td>An optional specific handler ID returned by <code>subscribeToChange</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true` if the listener is unsubscribed, or `false` if it is not found.

### `enableCaching`

Enables time-based caching of `read` and `readDownsampled` results for a specific measurement. Repeated identical queries within the TTL return the cached result instead of querying the database. Concurrent identical queries share a single database request.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>measurement</code></td><td>The name of the measurement to cache.</td><td>string</td></tr><tr><td><code>ttlMs</code></td><td>The time-to-live of cached results in milliseconds. Default 30000.</td><td>integer</td></tr></tbody></table>

#### Output

Returns nothing.

#### Example

```yaml
# measurement
production_line
# ttlMs
30000
```

### `disableCaching`

Disables caching for a specific measurement and purges all cached results.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>measurement</code></td><td>The name of the measurement.</td><td>string</td></tr></tbody></table>

#### Output

Returns nothing.

## Database management

### `delete` (data)

Deletes data from a measurement over a specified time range. Not to be confused with [`delete` (instance)](#delete-instance), which removes the instance.

{% hint style="danger" %}

#### Irreversible action

This permanently deletes the measurement data. You cannot undo this action.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="94.0738525390625">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>bucket</code></td><td></td><td>The name of the bucket.</td><td>string</td></tr><tr><td><code>measurement</code></td><td></td><td>The name of the measurement to delete.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>start</code></td><td>The start time. Default <code>1970-01-01</code>.</td><td>string</td></tr><tr><td></td><td><code>stop</code></td><td>The end time. Default is the current time.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# bucket
D
# measurement
test_data
# options
start: -1h
```

#### Output

Returns `true` when the deletion succeeds.

### `flush`

Manually forces buffered pending writes to send to the database immediately. Use this during testing or before shutting down a process to prevent data loss.

#### Parameters

None.

#### Output

Returns nothing. Throws an error if flushing fails.

### `reset`

Deletes all data from all measurements in all buckets. The buckets remain intact but empty.

{% hint style="danger" %}

#### Irreversible action

This permanently deletes all data associated with the instance. You cannot undo this action.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` when the reset succeeds.

### `listBuckets`

Retrieves all available buckets in the connected organization.

#### Parameters

None.

#### Output

Returns an array of bucket objects.

```json
[
  { "name": "D", "id": "...", "retentionPeriod": 86400 },
  { "name": "F", "id": "...", "retentionPeriod": 0 }
]
```

### `listMeasurements`

Lists detailed information about all measurements across all buckets.

#### Parameters

<table><thead><tr><th width="112.963134765625">Input</th><th width="161.6666259765625">Key</th><th width="391.5185546875">Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>includeStats</code></td><td>Calculates row count and cardinality when set to <code>true</code>. This operation can be slow. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>statsRangeStart</code></td><td>The start of the time range for calculations. Default <code>-1y</code>.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# options
includeStats: true
```

#### Output

Returns an array of objects containing measurement details.

```json
[
  {
    "name": "production_line",
    "bucket": "D",
    "fields": ["cycle_time", "yield"],
    "tags": ["line_id"],
    "stats": { "rowCount": 500, "seriesCardinality": 1 }
  }
]
```

### `getMeasurementDetails`

Retrieves the schema fields and tags of a specific measurement in a bucket.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>bucket</code></td><td>The bucket name.</td><td>string</td></tr><tr><td><code>measurement</code></td><td>The measurement name.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# bucket
D
# measurement
production_line
```

#### Output

Returns an object detailing fields and tags.

```json
{
  "fields": ["cycle_time", "yield"],
  "tags": ["line_id", "location"]
}
```

### `getMeasurementStats`

Calculates row count and cardinality of a specific measurement over a given time range.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="99.629638671875">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>bucket</code></td><td></td><td>The bucket name.</td><td>string</td></tr><tr><td><code>measurement</code></td><td></td><td>The measurement name.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>start</code></td><td>The start time. Default <code>-30d</code>.</td><td>string</td></tr><tr><td></td><td><code>stop</code></td><td>The end time. Default <code>now()</code>.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# bucket
F
# measurement
errors
# options
start: -7d
```

#### Output

Returns an object detailing row count and cardinality.

```json
{
  "rowCount": 150,
  "seriesCardinality": 2
}
```


# Data store

The data store class provides an in-memory storage array to manage collections of data items or objects. Add, remove, update, and retrieve data points dynamically within your flows. Data remains in memory only and does not persist to disk. This class requires an instance. The code class name is `DataStore`.

### `create`

Creates a new, empty data store instance.

#### Parameters

None.

#### Output

Returns the data store instance.

### `push`

Adds an item to the end of the data store.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>item</code></td><td>The item or object to add to the data store.</td><td>any</td></tr></tbody></table>

#### Output

Returns the new total length of the data store as an integer.

#### Examples

```yaml
# item
id: 1
name: First Item
```

### `pop`

Removes and returns the last item from the end of the data store.

#### Parameters

None.

#### Output

Returns the removed item or object.

### `pushFront`

Adds an item to the front of the data store.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>item</code></td><td>The item or object to add.</td><td>any</td></tr></tbody></table>

#### Output

Returns the new total length of the data store as an integer.

### `popFront`

Removes and returns the first item from the front of the data store.

#### Parameters

None.

#### Output

Returns the removed item or object.

### `get`

Retrieves the item at a specific zero-based index.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>index</code></td><td>The zero-based index of the item to retrieve.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the item at the specified index.

### `set`

Replaces the value of an item at a specific zero-based index.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>index</code></td><td>The zero-based index of the item to update.</td><td>integer</td></tr><tr><td><code>value</code></td><td>The new value to assign to the index.</td><td>any</td></tr></tbody></table>

#### Output

Returns nothing.

### `update`

Updates an item by merging new properties into it. The function matches items using an explicit lookup condition or an implicit ID field.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>data</code></td><td></td><td>An object containing the new properties to merge into the item.</td><td>object</td></tr><tr><td></td><td><code>id</code></td><td>The unique identifier used to match the target item if you omit the <code>where</code> input.</td><td>any</td></tr><tr><td><code>where</code></td><td></td><td>An optional selection object containing a single key-value pair to locate the item.</td><td>object</td></tr></tbody></table>

#### Output

Returns nothing.

#### Examples

**Update with where condition**

Finds the item where `email` equals `test@example.com` and modifies its status property.

```yaml
# data
status: archived
# where
email: test@example.com
```

**Update with implicit ID**

Matches the target item using the provided `id` property because no `where` input is defined.

```yaml
# data
id: 123
status: completed
```

### `length`

Returns the current number of items in the data store.

#### Parameters

None.

#### Output

Returns the total count of items as an integer.

### `indexOf`

Returns the zero-based index of the first occurrence of a specific item.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>item</code></td><td>The item to search for.</td><td>any</td></tr></tbody></table>

#### Output

Returns the zero-based index as an integer, or `-1` if the item does not exist.

### `includes`

Checks whether the data store contains a specific item.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>item</code></td><td>The item to search for.</td><td>any</td></tr></tbody></table>

#### Output

Returns `true` if the item exists, or `false` if it does not.

### `removeAt`

Removes the item at a specific zero-based index.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>index</code></td><td>The zero-based index of the item to remove.</td><td>integer</td></tr></tbody></table>

#### Output

Returns an array containing the removed item.

### `toArray`

Returns a shallow copy of all data store items as a standard array.

#### Parameters

None.

#### Output

Returns an array containing all stored items.

### `clear`

Removes all items from the data store.

#### Parameters

None.

#### Output

Returns nothing.

### `delete`

Removes the data store instance.

#### Parameters

None.

#### Output Implies

Returns nothing.

{% hint style="danger" %}

#### Permanent data loss

Deleting removes the instance configuration, and all stored data is permanently lost.
{% endhint %}


# Circular buffer

The circular buffer class implements a fixed-size ring buffer structure where elements connect end-to-end. When the buffer reaches capacity, new items overwrite the oldest entries. Use this class for streaming data where only the most recent values matter, such as maintaining the last 100 data points for a live chart widget.

Data remains in memory only and does not persist to disk. This class requires an instance. The code class name is `CircularBuffer`.

### `create`

Creates a new circular buffer instance with a specified capacity.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>capacity</code></td><td>The maximum number of items the buffer can hold. Default 100.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the circular buffer instance.

#### Examples

```yaml
# capacity
10
```

### `pushBack`

Adds an item to the back of the buffer. If the buffer is full, the item at the front is overwritten.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>value</code></td><td>The value or object to add.</td><td>any</td></tr></tbody></table>

#### Output

Returns nothing.

#### Examples

```yaml
# value
Another new item
```

### `pushFront`

Adds an item to the front of the buffer. If the buffer is full, the item at the back is overwritten.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>value</code></td><td>The value or object to add.</td><td>any</td></tr></tbody></table>

#### Output

Returns nothing.

### `popFront`

Removes and returns the item from the front of the buffer.

#### Parameters

None.

#### Output

Returns the removed value or object.

### `popBack`

Removes and returns the item from the back of the buffer.

#### Parameters

None.

#### Output

Returns the removed value or object.

### `getBuffer`

Returns all items currently inside the buffer as a standard array, ordered from front to back.

#### Parameters

None.

#### Output

Returns an array containing all stored values.

### `getSize`

Returns the current number of items stored in the buffer.

#### Parameters

None.

#### Output

Returns the current item count as an integer.

### `getCapacity`

Returns the maximum number of items the buffer can hold.

#### Parameters

None.

#### Output

Returns the buffer capacity configuration as an integer.

### `clear`

Removes all contents and empties the buffer.

#### Parameters

None.

#### Output

Returns `true`.

### `delete`

Removes the circular buffer instance.

#### Parameters

None.

#### Output

Returns nothing.

{% hint style="danger" %}

#### Permanent data loss

Deleting removes the instance configuration. All buffered data is permanently lost.
{% endhint %}


# Utilities

Utilities provide core data processing, timing, and asset generation features without requiring external systems. Use these classes to manage internal App logic and behavior.

## Available utility classes

<table><thead><tr><th width="220">Class</th><th>Description</th></tr></thead><tbody><tr><td><a href="/pages/cH4jhGd1rn6Aua5ON57y">Barcode generation</a></td><td>Generates 1D and 2D barcodes or QR codes as images or binary data.</td></tr><tr><td><a href="/pages/eVHdT6nZZ4oadlpDUBBr">Counter</a></td><td>Manages numerical values, such as production counts or sequence numbers.</td></tr><tr><td><a href="/pages/GlLOydboxYJGWAlcJE2B">Cron</a></td><td>Schedules automated tasks using standard cron expressions.</td></tr><tr><td><a href="/pages/xkkMu9fT0xvrfY7MH8DL">Data processing</a></td><td>Manipulates data by merging objects, filtering arrays, or mapping value ranges.</td></tr><tr><td><a href="/pages/xmFIQfq0xteO150LaZRn">Data simulation</a></td><td>Generates synthetic data points to test logic before connecting physical hardware.</td></tr><tr><td><a href="/pages/qTjfhcKrJhpcsBkMiCrF">Event simulation</a></td><td>Triggers mock events to verify that reactive flows respond correctly.</td></tr><tr><td><a href="/pages/7MOSJiISKmFuRjtXQMEQ">PDF processing</a></td><td>Splits, merges, or modifies existing PDF documents.</td></tr><tr><td><a href="/pages/K3yuOEOZG5xK9U2HN1qE">PDF templates</a></td><td>Generates PDF documents by merging App data with pre-designed layouts.</td></tr><tr><td><a href="/pages/NXjFC8OfW5Y6ejpPhW7E">Stopwatch</a></td><td>Measures time intervals using a high-resolution timer.</td></tr><tr><td><a href="/pages/BxdJVwFoILLisS5joFkM">Timer</a></td><td>Runs countdowns, maps progress to custom ranges, and introduces delays into flows.</td></tr><tr><td><a href="/pages/mxGhEdfwOMTRDrmbnnJg">Users</a></td><td>Manages users and App access programmatically.</td></tr></tbody></table>

{% hint style="info" %}

#### Testing with simulated data

Use data and event simulation nodes to test logic during the initial development phase. This verifies that dashboards and databases work correctly before connecting to a physical PLC or sensor. Once the logic works, replace the simulation classes with actual [connectors](/app-builder/build-backend/functions/connectors).
{% endhint %}


# Barcode generation

With barcode generation, you can create over 100 types of 1D and 2D barcodes and receive them as base64-encoded PNG images. The utility class provides static functions only, meaning you do not need to create an instance before calling them. The code class name is `Barcode`.

### `generateBarcode`

Creates a barcode image from the specified type, text, and options.

#### Parameters

See the [options reference](https://github.com/bwipp/postscriptbarcode/wiki/Options-Reference) for a full list of available configuration keys.

<table><thead><tr><th width="120">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>type</code></td><td></td><td>The barcode type, for example <code>qrcode</code>, <code>code128</code>, <code>ean13</code>, or <code>pdf417</code>. See the full list of <a href="https://github.com/metafloor/bwip-js/wiki/BWIPP-Barcode-Types">supported types</a>.</td><td>string</td></tr><tr><td><code>text</code></td><td></td><td>The text or data to encode into the barcode.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>scale</code></td><td>Sets both the x-axis and y-axis scaling factors. Must be an integer greater than 0.</td><td>integer</td></tr><tr><td></td><td><code>scaleX</code></td><td>The x-axis scaling factor. Must be an integer greater than 0. Default 2.</td><td>integer</td></tr><tr><td></td><td><code>scaleY</code></td><td>The y-axis scaling factor. Must be an integer greater than 0. Defaults to the value of <code>scaleX</code>.</td><td>integer</td></tr><tr><td></td><td><code>width</code></td><td>Bar width in millimeters.</td><td>integer</td></tr><tr><td></td><td><code>height</code></td><td>Bar height in millimeters.</td><td>integer</td></tr><tr><td></td><td><code>includeText</code></td><td>Shows the human-readable text below the barcode. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>textAlign</code></td><td>Alignment of the human-readable text: <code>left</code>, <code>center</code>, <code>right</code>, or <code>justify</code>. Default center.</td><td>string</td></tr><tr><td></td><td><code>rotate</code></td><td>Rotates the image: <code>N</code> (normal), <code>R</code> (right 90 degrees), <code>L</code> (left 90 degrees), or <code>I</code> (180 degrees). Default N.</td><td>string</td></tr><tr><td></td><td><code>binaryText</code></td><td>By default the text string is encoded as UTF-8 binary bytes. If the text is already 8-bit encoded, set this to true to disable that behavior. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>padding</code></td><td>Space generated around the barcode.</td><td>integer</td></tr><tr><td></td><td><code>barColor</code></td><td>Bar color as an RGB, RRGGBB, or CCMMYYKK hex value, for example <code>0F7180</code>.</td><td>string</td></tr><tr><td></td><td><code>textColor</code></td><td>Text color as an RGB, RRGGBB, or CCMMYYKK hex value.</td><td>string</td></tr><tr><td></td><td><code>backgroundColor</code></td><td>Background color as an RGB, RRGGBB, or CCMMYYKK hex value.</td><td>string</td></tr><tr><td></td><td><code>borderColor</code></td><td>Border color as an RGB, RRGGBB, or CCMMYYKK hex value.</td><td>string</td></tr></tbody></table>

#### Output

Returns a base64-encoded string representing the generated PNG image (for example, `iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACt...`). Throws an error if the type or text is invalid.

#### Examples

**Simple QR code**

Generates a standard QR code for a URL.

```yaml
# type
qrcode

# text
https://heisenware.com
```

**Styled Code 128 barcode**

Creates a `code128` barcode, scales it, includes the human-readable text, and applies custom colors.

```yaml
# type
code128

# text
12345678

# options
scale: 3
includeText: true
barColor: 0F7180
textColor: 0F7180
```

**Rotated EAN-13 barcode**

Generates an `ean13` barcode (which requires a 12-digit input) and rotates it 90 degrees to the right.

```yaml
# type
ean13

# text
123456789012

# options
scale: 4
rotate: R
```


# Counter

With a counter, you maintain a numerical value, for example a production count or sequence number. You can increment, decrement, and reset the count. You must create an instance of the counter to use it. The code class name is `Counter`.

### `create`

Creates a new counter instance, optionally starting from an initial value.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>initial</code></td><td>The number to start counting from. Default 0.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the name of the created instance.

#### Example

```yaml
# initial
10
```

### `delete`

Deletes a counter instance.

#### Parameters

None.

#### Output

Returns `true` upon removal.

{% hint style="danger" %}

#### Irreversible action

Deleting removes the instance configuration.
{% endhint %}

### `increment`

Increments the counter's value by one.

#### Parameters

None.

#### Output

Returns the new count as an integer.

### `decrement`

Decrements the counter's value by one.

#### Parameters

None.

#### Output

Returns the new count as an integer.

### `reset`

Resets the counter back to its initial value. You can optionally provide a new initial value to use for this and all future resets. A value of 0 cannot be set as a new initial value; in that case the counter resets to the previously configured initial value.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>initial</code></td><td>An optional new initial value.</td><td>integer</td></tr></tbody></table>

#### Output

Returns nothing.

#### Example

```yaml
# initial
100
```

### `getCount`

Retrieves the current value of the counter.

#### Parameters

None.

#### Output

Returns the current count as an integer.


# Cron

With cron, you schedule tasks that run automatically at specific times or intervals, defined in the standard cron expression format of the underlying `node-cron` library. This is useful for recurring jobs such as generating daily reports, performing nightly backups, or sending scheduled notifications. The code class name is `Cron`. This class requires an instance to schedule tasks, though it includes a static utility function for verification.

## Understanding cron expressions

A cron expression is a string of five or six fields separated by spaces that represents a time schedule. Each field specifies a different unit of time:

```
┌─────────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌─────────── day of month (1 - 31)
│ │ │ ┌───────── month (1 - 12)
│ │ │ │ ┌─────── day of week (0 - 6) (0 is Sunday)
│ │ │ │ │
* * * * *
```

### Special characters

* `*` represents "every" (such as every hour when used in the hour field).
* `,` specifies a list of values (such as `1,15,30` to trigger at minutes 1, 15, and 30).
* `-` defines a range of values (such as `9-17` to trigger every hour from 9 AM to 5 PM).
* `/` specifies step values (such as `*/15` to trigger every 15 minutes).

## Static functions

These functions are called directly on the class and do not require you to create an instance.

### `validate`

Checks if a cron expression string is syntactically valid.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>expression</code></td><td>The cron expression string to validate.</td><td>string</td></tr></tbody></table>

#### Output

Returns `true` if the expression is valid, or `false` if invalid.

#### Example

```yaml
# expression
0 9 * * 1-5
```

## Instance functions

You must create an instance to use these functions. All functions except `create`, `delete`, and `schedule` require a previously scheduled task.

### `create`

Creates a new, empty cron scheduler instance. The task itself is defined and started using the `schedule` function.

#### Parameters

None.

#### Output

Returns the name of the created instance.

### `delete`

Deletes a cron instance.

#### Parameters

None.

#### Output

Returns `true` upon removal.

{% hint style="danger" %}

#### Irreversible action

Deleting removes the instance configuration.
{% endhint %}

### `schedule`

Defines a task and schedules it to run based on a cron expression. The scheduler starts automatically when you call this function.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>expression</code></td><td></td><td>A valid cron expression string.</td><td>string</td></tr><tr><td><code>listener</code></td><td></td><td>The callback function that executes each time the schedule triggers.</td><td>callback</td></tr><tr><td><code>options</code></td><td><code>timezone</code></td><td>The timezone for the schedule (such as <code>America/New_York</code> or <code>Europe/Berlin</code>). If omitted, the system uses the server's local timezone.</td><td>string</td></tr><tr><td></td><td><code>noOverlap</code></td><td>Prevents the task from starting a new execution while the previous execution is still running. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>maxExecutions</code></td><td>Limits the total number of times the task runs before it is automatically destroyed.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the string `scheduled`.

#### Examples

**Example 1: Run a task every 15 minutes**

```yaml
# expression
*/15 * * * *

# listener
<callback>
```

**Example 2: Run a task at 9:00 AM and 5:00 PM every day**

```yaml
# expression
0 9,17 * * *

# listener
<callback>
```

**Example 3: Run a cleanup job at 1:30 AM every Saturday and Sunday**

```yaml
# expression
30 1 * * 6,0

# listener
<callback>
```

### `start`

Starts the task scheduler. You only need to call this if you have previously stopped the scheduler using `stop`, since `schedule` starts the task automatically. This function does nothing if the scheduler is already running.

#### Parameters

None.

#### Output

Returns `true`.

### `stop`

Stops the task scheduler. The scheduled task does not run again until you call `start`.

#### Parameters

None.

#### Output

Returns `true`.

### `execute`

Manually executes the task's function immediately, outside of its regular schedule. This is useful for testing or triggering on-demand runs.

#### Parameters

None.

#### Output

Returns the return value of the task function.

### `getStatus`

Retrieves the current lifecycle state of the task.

#### Parameters

None.

#### Output

Returns a string representing the current state:

* `stopped`: The scheduler is not running.
* `idle`: The scheduler is running, but the task is not executing.
* `running`: The task is actively executing.
* `destroyed`: The task is permanently removed.

### `getNextRun`

Retrieves the next scheduled run time for the task.

#### Parameters

None.

#### Output

Returns a date object representing the next run time, or `null` if the task is stopped or destroyed.

### `destroy`

Permanently deactivates the task and cleans up all internal resources. You cannot restart a destroyed task.

{% hint style="danger" %}

#### Irreversible action

Destroying a task removes its configuration permanently.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true`.


# Data processing

The data processing utility class provides a collection of functions for common data manipulation, transformation, and logical operations. Use these functions to work with arrays and objects, handle JSON payloads, map numerical value ranges, and delay data flows. All functions in this class are static, meaning you do not need to create an instance before using them. The code class name is `Tools`.

### `echo`

Returns the exact input value it receives.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>value</code></td><td>Any input argument to return.</td><td>any</td></tr></tbody></table>

#### Output

Returns the unchanged input value.

### `combine`

Combines two or more arguments into a single array. Undefined values beyond the first two arguments are ignored.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>arg1</code>, <code>arg2</code>, ...</td><td>An arbitrary number of arguments to combine into an array.</td><td>any</td></tr></tbody></table>

#### Example

```yaml
# arg1
123
# arg2
"hello"
# arg3
{ "key": "value" }
```

#### Output

Returns the combined array:

```json
[
  123,
  "hello",
  { "key": "value" }
]
```

### `mergeObjects`

Merges two or more objects into a single new object. If the same key exists in multiple objects, the value from the last object in the argument list overwrites the previous values. The function ignores any arguments that are not plain objects (including arrays).

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>arg1</code>, <code>arg2</code>, ...</td><td>Two or more objects to merge together.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# arg1
{ "name": "John", "status": "active" }
# arg2
{ "status": "inactive", "id": 123 }
```

#### Output

Returns the merged object:

```json
{
  "name": "John",
  "status": "inactive",
  "id": 123
}
```

### `arrayPush`

Pushes one or more items to the end of an array. If an item is itself an array, the function unpacks its elements and adds them individually to the base array. If the first input is not an array, the function wraps it in one; `null` or an empty input starts a new array.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>array</code></td><td>The destination input array.</td><td>array</td></tr><tr><td><code>items</code></td><td>Any number of items to push to the end of the array.</td><td>any</td></tr></tbody></table>

#### Example

```yaml
# array
[1, 2]
# items
[ 3, 4, [5, 6] ]
```

#### Output

Returns the updated array:

```json
[1, 2, 3, 4, 5, 6]
```

### `mapRange`

Maps a numerical value from an original range to a new range. The function rounds the final result to the nearest integer.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>value</code></td><td></td><td>The numerical value to map.</td><td>number</td></tr><tr><td><code>options</code></td><td><code>origMin</code></td><td>The minimum value of the original range.</td><td>number</td></tr><tr><td></td><td><code>origMax</code></td><td>The maximum value of the original range.</td><td>number</td></tr><tr><td></td><td><code>newMin</code></td><td>The minimum value of the new range.</td><td>number</td></tr><tr><td></td><td><code>newMax</code></td><td>The maximum value of the new range.</td><td>number</td></tr></tbody></table>

#### Example

Map a sensor value (0 to 1023) to a percentage scale (0 to 100):

```yaml
# value
512
# options
origMin: 0
origMax: 1023
newMin: 0
newMax: 100
```

#### Output

Returns the mapped integer value: `50`

### `delay`

Returns the provided value after a configurable time delay. This function executes asynchronously.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>value</code></td><td></td><td>The value to return after the delay.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>timeout</code></td><td>The delay duration in milliseconds. Default 1000.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the unchanged input value after the specified time delay.

### `areAllParamsTrue`

Applies a logical AND operation. This function checks if the exact number of specified arguments are all truthy (not `false`, `0`, `""`, `null`, or `undefined`).

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>nParams</code></td><td>The exact number of arguments that must be provided and evaluate to truthy.</td><td>integer</td></tr><tr><td><code>args</code></td><td>The arguments to evaluate.</td><td>any</td></tr></tbody></table>

#### Examples

**Scenario 1: All elements match and evaluate to truthy**

```yaml
# nParams
3
# args
[true, "hello", 1]
```

Output: `true` (3 arguments were provided and all evaluate to truthy)

**Scenario 2: Insufficient truthy parameters provided**

```yaml
# nParams
3
# args
[true, ""]
```

Output: `false` (only 2 truthy arguments were provided instead of 3)

#### Output

Returns `true` if all arguments match `nParams` and evaluate to truthy; otherwise, returns `false`.

### `isOneOrMoreParamTrue`

Applies a logical OR operation. This function checks if at least one of the provided arguments evaluates to truthy.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>args</code></td><td>Any number of input parameters to check.</td><td>any</td></tr></tbody></table>

#### Example

```yaml
# args
[false, 0, "hello", null]
```

#### Output

Returns `true` if at least one argument evaluates to truthy (because `"hello"` is truthy); otherwise, returns `false`.

### `jsonStringify`

Converts a JavaScript runtime value (such as an object or array) into a standard JSON string.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>value</code></td><td>The JavaScript object or array to convert.</td><td>any</td></tr></tbody></table>

#### Example

```yaml
# value
{ "name": "John", "is_active": true, "roles": ["admin", "editor"] }
```

#### Output

Returns the generated JSON string:

`'{"name":"John","is_active":true,"roles":["admin","editor"]}'`

### `jsonParse`

Converts a valid JSON string back into its corresponding JavaScript object or value representation.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>text</code></td><td>A valid JSON string to parse.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# text
'{"name":"John","is_active":true,"roles":["admin","editor"]}'
```

#### Output

Returns the parsed JavaScript entity. Throws an error if the string is not valid JSON.

```json
{
  "name": "John",
  "is_active": true,
  "roles": ["admin", "editor"]
}
```

### `flatten`

Takes a nested JavaScript object and flattens it into a single-level object structure by generating dot-delimited keys.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>target</code></td><td></td><td>The nested target object to flatten.</td><td>object</td></tr><tr><td><code>options</code></td><td><code>delimiter</code></td><td>A custom delimiter string to separate keys instead of the default dot <code>.</code>.</td><td>string</td></tr><tr><td></td><td><code>safe</code></td><td>If true, preserves arrays and their contents intact instead of flattening their indexes. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>maxDepth</code></td><td>The maximum number of nested levels to flatten.</td><td>integer</td></tr></tbody></table>

#### Example

```yaml
# target
{
  "user": {
    "name": "John",
    "address": {
      "city": "New York"
    }
  },
  "tags": ["a", "b"]
}
```

#### Output

Returns the flattened object:

```json
{
  "user.name": "John",
  "user.address.city": "New York",
  "tags.0": "a",
  "tags.1": "b"
}
```

### `unflatten`

The inverse operation of `flatten`. Takes a flat object containing delimited keys and converts it back into a deeply nested object structure.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>target</code></td><td></td><td>The flat target object to unflatten.</td><td>object</td></tr><tr><td><code>options</code></td><td><code>delimiter</code></td><td>A custom delimiter string to identify nested breaks instead of a dot.</td><td>string</td></tr><tr><td></td><td><code>safe</code></td><td>If true, preserves arrays and their nested contents intact. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>object</code></td><td>If true, prevents the automatic instantiation of arrays when unflattening. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>override</code></td><td>If true, overwrites existing keys if they cannot accommodate a newly encountered nested object value. Default false.</td><td>boolean</td></tr></tbody></table>

#### Example

```yaml
# target
{
  "user.name": "John",
  "user.address.city": "New York"
}
```

#### Output

Returns the unflattened nested object structure:

```json
{
  "user": {
    "name": "John",
    "address": {
      "city": "New York"
    }
  }
}
```

### `mergeArrays`

Merges multiple arrays by combining the objects located at corresponding indexes. The function truncates the final output array to match the length of the shortest provided input array. Non-object elements are included with a key of an underscore `_` followed by the source array index.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>args</code></td><td>Multiple arrays of objects to merge together.</td><td>array</td></tr></tbody></table>

#### Example

```yaml
# args
[
  [ { "a": 1 }, { "b": 2 } ],
  [ { "c": 3 }, { "d": 4, "e": 5 } ]
]
```

#### Output

Returns the merged index array:

```json
[
  { "a": 1, "c": 3 },
  { "b": 2, "d": 4, "e": 5 }
]
```

### `combineArrays`

Combines multiple arrays similarly to `mergeArrays`, but appends an underscore `_` followed by the source array index to each object key. This prevents key collisions when the arrays contain objects with identical keys.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>args</code></td><td>Multiple arrays to combine.</td><td>array</td></tr></tbody></table>

#### Example

```yaml
# args
[
  [ { "value": 10 }, { "value": 20 } ],
  [ { "value": 30 }, { "value": 40 } ]
]
```

#### Output

Returns the indexed combination array:

```json
[
  { "value_0": 10, "value_1": 30 },
  { "value_0": 20, "value_1": 40 }
]
```

### `groupArrays`

Groups and merges objects compiled from multiple separate arrays based on a shared property key or an array of designated keys. This utility provides an efficient way to execute client-side joins across distinct data streams.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>keys</code></td><td>The property key string or array of key strings to group target data items by.</td><td>string or array</td></tr><tr><td><code>args</code></td><td>Multiple arrays composed of data objects to group and merge.</td><td>array</td></tr></tbody></table>

#### Example

Grouping distinct collections using a shared `id` key:

```yaml
# keys
id
# args
[
  [ { "id": 1, "name": "Alice" }, { "id": 2, "name": "Bob" } ],
  [ { "id": 1, "age": 25 }, { "id": 2, "age": 30 } ]
]
```

#### Output

Returns the grouped and structurally merged array:

```json
[
  { "id": 1, "name": "Alice", "age": 25 },
  { "id": 2, "name": "Bob", "age": 30 }
]
```

### `renameObjectKeys`

Generates a new object with renamed keys based on a specified mapping configuration. Keys not present in the mapping remain unchanged.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>object</code></td><td>The target object whose keys require renaming.</td><td>object</td></tr><tr><td><code>keyMapping</code></td><td>A dictionary object where each key represents the original property string and its corresponding value defines the new key string identifier.</td><td>object</td></tr></tbody></table>

#### Example

```yaml
# object
{ "first_name": "John", "last_name": "Doe" }
# keyMapping
{ "first_name": "firstName", "last_name": "lastName" }
```

#### Output

Returns the object with updated keys:

```json
{
  "firstName": "John",
  "lastName": "Doe"
}
```

### `base64Decode`

Decodes a base64-encoded string back into its original text representation.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>base64String</code></td><td>The base64 encoded source string.</td><td>string</td></tr><tr><td><code>encoding</code></td><td>The character encoding of the returned string. Default <code>utf8</code>.</td><td>string</td></tr></tbody></table>

#### Example

```yaml
# base64String
SGVsbG8gV29ybGQ=
```

#### Output

Returns the decoded text string: `Hello World`

### `base64Encode`

Encodes a plain text string or binary byte collection into a base64 string representation.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>bytes</code></td><td>The input text string or raw bytes to encode.</td><td>any</td></tr></tbody></table>

#### Example

```yaml
# bytes
Hello World
```

#### Output

Returns the generated base64-encoded string: `SGVsbG8gV29ybGQ=`

### `memory`

Passes its input value directly to its output immediately upon any input update. This function has input and output slots but no visible trigger; it behaves as if its trigger were permanently set to on input update.

<figure><img src="/files/rAOJUWaYGmae2EqIVyYz" alt=""><figcaption></figcaption></figure>

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>value</code></td><td>Any input argument to pass through.</td><td>any</td></tr></tbody></table>

#### Output

Returns the unchanged input value.

### `trigger`

A function without inputs. Use it to start flows manually or on a schedule via its trigger.

#### Parameters

None.

#### Output

Returns the current Unix timestamp in milliseconds.

{% hint style="info" %}

#### Toolbar shortcuts

The Backend Builder toolbar includes shortcuts to create `memory`, `echo`, `combine`, and `trigger` nodes directly.
{% endhint %}


# Data simulation

This article lists and explains all available simulator functions.

The data simulation class generates random and mock data for testing, prototyping, and creating demonstrations without requiring real information. These functions create numbers, strings, and complex structured datasets such as personal profiles, geographic coordinates, and time-series logs. This class provides static functions only and does not require an instance. The code class name is `Simulator`.

## Basic values

### `randomInteger`

Returns a random whole number between a minimum and a maximum value (both inclusive).

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>min</code></td><td>The minimum possible integer. Default 0.</td><td>integer</td></tr><tr><td></td><td><code>max</code></td><td>The maximum possible integer. Default 99999.</td><td>integer</td></tr></tbody></table>

#### Output

Returns a random integer.

#### Example

```yaml
# options
min: 1
max: 10
```

### `randomNumber`

Returns a random floating-point number between a minimum and a maximum value.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>min</code></td><td>The minimum possible number. Default 0.</td><td>number</td></tr><tr><td></td><td><code>max</code></td><td>The maximum possible number (exclusive). Default 1.</td><td>number</td></tr></tbody></table>

#### Output

Returns a random floating-point number.

#### Example

```yaml
# options
min: 0
max: 100
```

### `randomString`

Generates a string of a specified length composed of random printable characters from `!` to `}` (character codes 33 to 125).

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>length</code></td><td>The desired length of the string. Maximum is 2^20. Default 10.</td><td>integer</td></tr></tbody></table>

#### Output

Returns a random string.

#### Example

```yaml
# length
12
```

### `randomText`

Generates random placeholder text in a lorem ipsum style to populate text fields and layout paragraphs.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="180">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>count</code></td><td>The number of units to generate. Default 1.</td><td>integer</td></tr><tr><td></td><td><code>units</code></td><td>The type of unit to generate: <code>words</code>, <code>sentences</code>, or <code>paragraphs</code>. Default <code>sentences</code>.</td><td>string</td></tr><tr><td></td><td><code>format</code></td><td>The output format, either <code>plain</code> or <code>html</code>. Default <code>plain</code>.</td><td>string</td></tr><tr><td></td><td><code>sentenceLowerBound</code></td><td>The minimum number of words per sentence.</td><td>integer</td></tr><tr><td></td><td><code>sentenceUpperBound</code></td><td>The maximum number of words per sentence.</td><td>integer</td></tr><tr><td></td><td><code>paragraphLowerBound</code></td><td>The minimum number of sentences per paragraph.</td><td>integer</td></tr><tr><td></td><td><code>paragraphUpperBound</code></td><td>The maximum number of sentences per paragraph.</td><td>integer</td></tr><tr><td></td><td><code>suffix</code></td><td>The line ending used between units. Defaults to the system line break.</td><td>string</td></tr></tbody></table>

#### Output

Returns a string of random text.

#### Examples

Example 1: Generate words

```yaml
# options
count: 5
units: words
```

Example 2: Generate paragraphs with HTML tags

```yaml
# options
count: 1
units: paragraphs
format: html
```

### `error`

Throws an execution error with a specified or random message to test error-handling logic.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>customMessage</code></td><td>An optional string to use as the error message. If omitted, the function uses a random lorem ipsum sentence.</td><td>string</td></tr></tbody></table>

#### Output

Throws an execution error.

## Complex structures

### `randomObject`

Generates an object with a random number of keys and values of various types.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>min</code></td><td>The minimum number of key-value pairs. Default 3.</td><td>integer</td></tr><tr><td></td><td><code>max</code></td><td>The maximum number of key-value pairs. Default 7.</td><td>integer</td></tr><tr><td></td><td><code>allowNesting</code></td><td>Allows values to be other random objects. Default true.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns a random object.

### `randomArrayOfIntegers`

Returns an array of random integers.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>length</code></td><td>The length of the array. Default 10.</td><td>integer</td></tr></tbody></table>

#### Output

Returns an array of integers.

### `randomArrayOfNumbers`

Returns an array of random floating-point numbers.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>length</code></td><td>The length of the array. Default 10.</td><td>integer</td></tr></tbody></table>

#### Output

Returns an array of numbers.

### `randomArrayOfDigits`

Returns an array of random single digits (0 to 9).

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>length</code></td><td>The length of the array. Default 10.</td><td>integer</td></tr></tbody></table>

#### Output

Returns an array of integers.

### `randomArrayOfStrings`

Returns an array of random words.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>length</code></td><td>The length of the array. Default 10.</td><td>integer</td></tr></tbody></table>

#### Output

Returns an array of strings.

### `randomArrayOfObjects`

Returns an array of random objects with flat, non-nested values.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>length</code></td><td></td><td>The length of the array. Default 10.</td><td>integer</td></tr><tr><td><code>options</code></td><td><code>min</code></td><td>The minimum number of entries per object. Default 3.</td><td>integer</td></tr><tr><td></td><td><code>max</code></td><td>The maximum number of entries per object. Default 7.</td><td>integer</td></tr></tbody></table>

#### Output

Returns an array of objects.

## Specialized datasets

### `randomNumericData`

Generates numeric datasets using a Gaussian distribution to create realistic random fluctuations around a mean value, typically used for charts.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>nDataSets</code></td><td>The number of separate datasets to generate. Default 1.</td><td>integer</td></tr><tr><td></td><td><code>nDataPoints</code></td><td>The number of data points per dataset. Default 100.</td><td>integer</td></tr><tr><td></td><td><code>addTimeAxis</code></td><td>Adds a <code>date</code> field to each data point, incrementing by one second per point. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>timeFormat</code></td><td>The format of the <code>date</code> field when <code>addTimeAxis</code> is true: <code>epoch</code>, <code>iso</code>, <code>string</code>, or <code>object</code>. Default <code>epoch</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns a single array of numbers if `nDataSets` is 1 and `addTimeAxis` is false. Otherwise returns an array of objects with one key per dataset (`dataset0`, `dataset1`, ...) and, if enabled, the `date` field.

#### Examples

Example 1: Single dataset array

```yaml
# options
nDataSets: 1
nDataPoints: 5
```

Example 2: Multiple datasets with an ISO time axis

```yaml
# options
nDataSets: 2
nDataPoints: 3
addTimeAxis: true
timeFormat: iso
```

### `randomAddressData`

Returns an array of realistic address objects containing street, building number, city, state, and country fields.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>entries</code></td><td>The number of address objects to generate. Default 10.</td><td>integer</td></tr><tr><td></td><td><code>locale</code></td><td>The geographic locale format for the data: <code>DE</code> or <code>US</code>. Default <code>DE</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of address objects.

### `randomPersonData`

Returns an array of realistic personal identity records.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>entries</code></td><td>The number of person objects to generate. Default 10.</td><td>integer</td></tr><tr><td></td><td><code>locale</code></td><td>The regional locale format for names and data: <code>DE</code> or <code>US</code>. Default <code>DE</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of objects containing `avatar` (a base64-encoded random JPEG image), `title`, `firstName`, `lastName`, `company`, `phone`, `verified` (always `true`), `validUntil` (a random ISO date within the next 30 hours), and `note` (always empty).

### `randomChatData`

Generates an array of simple chat message objects with alternating `role` values (`You` and `ChatBot`) and random `content` to simulate a conversation.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>messages</code></td><td>The total number of chat messages to generate. Default 10.</td><td>integer</td></tr></tbody></table>

#### Output

Returns an array of chat message objects.

### `timelineData`

Generates randomized chronological timeline events spanning a specific duration and ending at the current time. This function supports tracking machine states, operator assignments, and work shifts.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="150">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>totalDurationHours</code></td><td>The total duration of the generated data in hours. Default 24.</td><td>number</td></tr><tr><td></td><td><code>includeState</code></td><td>Includes the machine state track (values <code>Running</code>, <code>Idle</code>, <code>Maintenance</code>, or <code>Error</code>). Default true.</td><td>boolean</td></tr><tr><td></td><td><code>includeOperator</code></td><td>Includes the operator assignment track. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>includeShift</code></td><td>Includes the work shift track. Default false.</td><td>boolean</td></tr><tr><td></td><td><code>timeFormat</code></td><td>The timestamp format: <code>epoch</code>, <code>iso</code>, <code>string</code>, or <code>object</code>. Default <code>epoch</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of timeline event objects with a `timestamp` and the enabled tracks.

### `randomPointInCircle`

Generates a random GPS coordinate within a specified radius of a central point.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>distance</code></td><td></td><td>The radius of the circle in meters. Default 5000.</td><td>integer</td></tr><tr><td><code>coord</code></td><td><code>lat</code></td><td>The latitude of the central coordinate point. Default 53.5511 (Hamburg, Germany).</td><td>number</td></tr><tr><td></td><td><code>lng</code></td><td>The longitude of the central coordinate point. Default 9.9937 (Hamburg, Germany).</td><td>number</td></tr></tbody></table>

#### Output

Returns a coordinate object containing `lat` and `lng` properties.

### Predefined reference datasets

These functions require no parameters and return static, predefined JSON datasets to test layout configurations and UI components (such as charts, data grids, or kanban boards) consistently:

* `kanbanData`: Returns structured columns and cards for a kanban board.
* `energyData`: Returns data tracking power metrics and energy sources.
* `populationDataset`: Returns historical demographic population data.
* `marketValueDataset`: Returns data tracking corporate market valuations.
* `australianMedalsDataset`: Returns statistics on historical Olympic medals.
* `populationVsAgeDataset`: Returns data correlating age groups and population distribution.

## Execution control

### `longExecution`

Simulates a long-running asynchronous process by pausing execution for a specified duration.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>time</code></td><td>The simulated execution duration in milliseconds.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the execution duration value after the specified delay.


# Event simulation

The event simulation class simulates various events to test and validate workflows. Generating mock events ensures that flows handle different scenarios and edge cases effectively. It also serves as a placeholder in a flow before you complete your App. To learn more about event handlers, see [callbacks](/app-builder/build-backend/functions#callbacks).

To access the event simulation functions, unfold Simulation > Events in the Function Explorer. This class requires an instance. The code class name is `Trigger`.

### `create`

Constructs a new event simulation instance.

#### Parameters

None.

#### Output

Returns the name of the created instance.

#### Example

<figure><img src="/files/hQimC1xFOpFPLwQ8xtxm" alt=""><figcaption><p>Create an event simulation instance</p></figcaption></figure>

### `triggerManually`

Triggers a manual event within the instance to activate the `onManualTrigger` listener.

#### Parameters

None.

#### Output

Returns `true`.

### `onManualTrigger`

Fires when you execute the `triggerManually` function within the same instance.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>listener</code></td><td>Callback that executes when the manual event triggers. Payload: a UNIX timestamp integer.</td><td>callback</td></tr></tbody></table>

#### Output

Returns the string `subscribed`.

#### Example

<figure><img src="/files/6TmfHkfI3vy23Z346A9F" alt=""><figcaption><p>The listener outputs the timestamp after a manual trigger</p></figcaption></figure>

### `startAutoTrigger`

Starts generating periodic automatic events at a specified interval.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>interval</code></td><td>The repetition interval in milliseconds. Default 1000.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the string `started`.

### `onAutoTrigger`

Fires periodically when an automatic trigger is active.

{% hint style="info" %}

#### Initializing the listener

You may need to trigger `onAutoTrigger` once to start reacting to automatically generated events after calling `startAutoTrigger`.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>listener</code></td><td>Callback that executes when the automatic event triggers. Payload: a UNIX timestamp integer.</td><td>callback</td></tr></tbody></table>

#### Output

Returns the string `subscribed`.

#### Example

<figure><img src="/files/xTlDdSpUX86uqm1LetUF" alt=""><figcaption><p>React periodically to automatic events</p></figcaption></figure>

### `stopAutoTrigger`

Stops the active automatic trigger and halts periodic event generation.

#### Parameters

None.

#### Output

Returns `true`.

#### Example

<figure><img src="/files/4AUir9NUyTAjS2fhDNUJ" alt=""><figcaption><p>Stop event generation</p></figcaption></figure>

### `triggerCallback`

Triggers an event that executes its own callback after a specified delay. To prevent infinite loops, the function does not react to the output of its own callback.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>listener</code></td><td>Callback that executes after the timeout delay.<br>Payload: a Unix timestamp in milliseconds.</td><td>callback</td></tr><tr><td><code>timeout</code></td><td>The delay duration in milliseconds before the callback executes. Default 3000.</td><td>integer</td></tr></tbody></table>

#### Output

Returns a string stating when the callback will run, for example `Calling back in 3 seconds`.

#### Example

<figure><img src="/files/lC02SOi6zJrgirrNY5M4" alt=""><figcaption><p>Callback execution after a timeout delay</p></figcaption></figure>

### `delete`

Removes the instance and clears its configuration.

{% hint style="danger" %}

#### Irreversible action

Deleting an instance removes its configuration permanently.
{% endhint %}

#### Parameters

None.

#### Output

Returns `true` upon removal.

#### Example

<figure><img src="/files/EcZqb8koLUh8JYGDarjr" alt=""><figcaption><p>Delete an event simulation instance</p></figcaption></figure>


# PDF processing

The PDF processing class provides static utility functions that create and manipulate PDF documents. It generates PDFs from structured JSON (`pdfmake` format), converts HTML content into PDFs, and merges multiple documents (PDF, PNG, JPG, and HEIC) into a single PDF file. This class contains static functions only and does not require an instance. The code class name is `Pdf`.

### `mergeDocuments`

Merges multiple source documents into a single PDF file. The function accepts PDFs, PNG images, or JPG images, and automatically converts the images to PDF pages before merging. HEIC images are supported when provided as file objects with a path. Entries that cannot be processed are skipped and logged.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>files</code></td><td>An array where each element is either a base64-encoded file string or an object containing a <code>path</code> property pointing to the file.</td><td>array</td></tr></tbody></table>

#### Output

Returns a file object representing the merged PDF file, including its path, name, size, and type. Returns nothing if the input is not a non-empty array.

#### Example

```yaml
# files
  - path: /shared/documents/report.pdf
  - path: /shared/documents/scan.png
```

### `createPdfFileFromJson`

Creates a new PDF file from a structured JSON object that follows the `pdfmake` document definition format. Use this format to control the PDF layout and content precisely. See the [pdfmake playground](http://pdfmake.org/playground.html) to test layouts.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>content</code></td><td></td><td>The content definition object or array following the <code>pdfmake</code> syntax.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>format</code></td><td>The page size (such as <code>A4</code>, <code>A5</code>, or <code>LETTER</code>). Default A4.</td><td>string</td></tr><tr><td></td><td><code>orientation</code></td><td>The page orientation: <code>portrait</code> or <code>landscape</code>. Default portrait.</td><td>string</td></tr></tbody></table>

#### Output

Returns a file object representing the generated PDF file.

#### Example

```yaml
# content
  - text: My Document Title
    style: header
  - This is a sample paragraph.
  - ul:
      - First list item
      - Second list item
# options
format: A4
orientation: portrait
```

### `createPdfBufferFromJson`

Creates a PDF from a `pdfmake` JSON object and returns it as a base64-encoded string instead of writing it to a file.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>content</code></td><td></td><td>The content definition object or array following the <code>pdfmake</code> syntax.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>format</code></td><td>The page size (such as <code>A4</code>, <code>A5</code>, or <code>LETTER</code>). Default A4.</td><td>string</td></tr><tr><td></td><td><code>orientation</code></td><td>The page orientation: <code>portrait</code> or <code>landscape</code>. Default portrait.</td><td>string</td></tr></tbody></table>

#### Output

Returns a base64-encoded string representing the generated PDF document.

#### Example

```yaml
# content
  - text: My Document Title
    style: header
# options
format: A4
```

### `createPdfFileFromHtml`

Converts an HTML string into a new PDF file.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>html</code></td><td></td><td>The HTML content string to convert.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>format</code></td><td>The page size. Default A4.</td><td>string</td></tr><tr><td></td><td><code>orientation</code></td><td>The page orientation: <code>portrait</code> or <code>landscape</code>. Default portrait.</td><td>string</td></tr><tr><td></td><td><code>tableAutoSize</code></td><td>Automatically sizes HTML tables. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>removeExtraBlanks</code></td><td>Removes extra blank spaces from the document. Default false.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns a file object representing the generated PDF file.

#### Example

```yaml
# html
<h1>Report Title</h1><p>This report was generated.</p>
# options
orientation: landscape
```

### `createPdfBufferFromHtml`

Converts an HTML string into a PDF and returns it as a base64-encoded string.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>html</code></td><td></td><td>The HTML content string to convert.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>format</code></td><td>The page size. Default A4.</td><td>string</td></tr><tr><td></td><td><code>orientation</code></td><td>The page orientation: <code>portrait</code> or <code>landscape</code>. Default portrait.</td><td>string</td></tr><tr><td></td><td><code>tableAutoSize</code></td><td>Automatically sizes HTML tables. Default true.</td><td>boolean</td></tr><tr><td></td><td><code>removeExtraBlanks</code></td><td>Removes extra blank spaces from the document. Default false.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns a base64-encoded string representing the generated PDF document.

#### Example

```yaml
# html
<h1>Report Title</h1><p>This report was generated.</p>
# options
orientation: landscape
```


# PDF templates

The PDF template class generates PDF documents by merging App data with layouts designed in the [PDF Template Editor](/app-builder/build-frontend/pdf-template-editor). Each template operates as an instance that contains the `fillTemplate` function for its layout. This class requires an instance. The code class name is `PdfTemplate`.

### `fillTemplate`

Merges data with the pre-designed layout and generates a completed document.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>values</code></td><td></td><td>A data object containing key-value pairs. The keys must exactly match the variable names configured for placeholders in the <a href="/pages/avZz4jNnzxnhvzfxSZH2">PDF Template Editor</a> (such as <code>firstName</code> or <code>orderDate</code>). Supports nested objects.</td><td>object</td></tr><tr><td><code>options</code></td><td><code>showEmptyVariables</code></td><td>Displays the variable name in angle brackets (such as <code>&#x3C;firstName></code>) for placeholders without a value. If false, leaves them empty. Default false.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns the populated PDF document as a base64-encoded string. If rendering fails, the function returns nothing and the error appears in the log. During development, the function node displays a preview of the rendered PDF layout. Store the output in a [database](/app-builder/build-backend/functions/storage/relational-database), display it in a media view widget, or send it as an [email](/app-builder/build-backend/functions/connectors/email) attachment.

<figure><img src="/files/SdCyM3PowVpKy5iZXU4C" alt=""><figcaption><p>The fillTemplate function node preview</p></figcaption></figure>

{% hint style="info" %}

#### Document generation

Each execution generates a new document and populates the entire template in a single operation. For templates with multiple fields, assemble the required data into a single structured object before passing it to the function.
{% endhint %}

#### Example

**Fill template layout**

```yaml
# values
name: John
surname: Doe
signature: iVBORw0KGgoAAAANSUhEUg...
# options
showEmptyVariables: true
```

## Full tutorial

See the step-by-step tutorial to build a dynamic acceptance report from start to finish:

[From Data to Document: Automating PDF Reports](/tutorials/app-templates/automating-pdf-reports)


# Stopwatch

The stopwatch class manages a high-resolution timer to measure time intervals. Start, stop, and reset the timer, or record lap snapshots of the elapsed time without stopping the main timer. Use this class to time operations, track activity, or manage time-based logic.

The class emits events (including `start`, `stop`, `reset`, `tick`, and `lap`) to trigger other functions or flows automatically in your Apps. This class requires an instance, but also provides static utility functions. The code class name is `Stopwatch`.

## Static functions

Use these functions without creating an instance.

### `formatTime`

Converts a duration in milliseconds into a formatted string. This helps display the outputs of `getElapsedTime` or `getLaps` in a human-readable format.

The `format` parameter replaces specific tokens with time values:

* `HH`: Hours, zero-padded (for example, `08`)
* `H`: Hours, unpadded (for example, `8`)
* `mm`: Minutes, zero-padded (for example, `05`)
* `m`: Minutes, unpadded (for example, `5`)
* `ss`: Seconds, zero-padded (for example, `01`)
* `s`: Seconds, unpadded (for example, `1`)
* `ms`: Milliseconds, padded to three digits (for example, `045`)

{% hint style="info" %}

#### Avoid token letters in literal text

The formatter replaces every occurrence of a token letter in the format string, including letters inside literal text. For example, a format like `m minutes` produces mangled output. Use only separator characters such as colons, periods, or spaces between tokens.
{% endhint %}

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>milliseconds</code></td><td>The duration to format.</td><td>integer</td></tr><tr><td><code>format</code></td><td>A string defining the output format. Default <code>HH:mm:ss.ms</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns the formatted time as a string.

#### Examples

**Default format**

Formats 125,500 milliseconds (2 minutes, 5 seconds, 500 ms) using the default format.

```yaml
# milliseconds
125500
```

Output: `00:02:05.500`

**Custom format**

Formats 3,601,000 milliseconds (1 hour, 1 second) using a custom format.

```yaml
# milliseconds
3601000
# format
H:mm:ss
```

Output: `1:00:01`

## Instance functions

You must create an instance to use these functions.

### `create`

Creates a new stopwatch instance initialized in the stopped state with an elapsed time of 0.

#### Parameters

None.

#### Output

Returns the name of the created instance.

### `delete`

Deletes a stopwatch instance.

#### Parameters

None.

#### Output

Returns `true` upon removal.

{% hint style="danger" %}

#### Irreversible action

Deleting removes the instance configuration.
{% endhint %}

### `start`

Starts or resumes the stopwatch and triggers the `start` event. If the stopwatch is already running, this function does nothing.

#### Parameters

None.

#### Output

Returns nothing.

### `stop`

Stops the stopwatch and triggers the `stop` event. The stopwatch saves and holds the current elapsed time until you call `start` again. If the stopwatch is already stopped, this function does nothing.

#### Parameters

None.

#### Output

Returns nothing.

### `reset`

Stops the stopwatch, resets the elapsed time and all recorded laps to zero, and triggers the `reset` event.

#### Parameters

None.

#### Output

Returns nothing.

### `lap`

Records the current elapsed time as a lap without stopping the stopwatch and triggers the `lap` event. If the stopwatch is not running, this function does nothing.

#### Parameters

None.

#### Output

Returns nothing.

### `getElapsedTime`

Returns the total elapsed time in milliseconds. This function works whether the stopwatch is running or stopped.

#### Parameters

None.

#### Output

Returns the elapsed time in milliseconds.

Example payload:

```json
15320.5
```

### `getLaps`

Returns an array of all recorded lap times.

#### Parameters

None.

#### Output

Returns an array of lap times in milliseconds.

Example payload:

```json
[
  5012.3,
  10050.1,
  15320.5
]
```

### `clearLaps`

Clears all recorded laps. This action does not stop or reset the main timer.

#### Parameters

None.

#### Output

Returns nothing.

### `isRunning`

Checks whether the stopwatch is running.

#### Parameters

None.

#### Output

Returns `true` if the stopwatch is running, or `false` if it is stopped.

### `getState`

Returns the current state of the stopwatch.

#### Parameters

None.

#### Output

Returns `running` if the stopwatch is running, or `stopped` if it is stopped.

### `setTickInterval`

Sets the update interval for the `tick` event. If the stopwatch is running, the new interval applies immediately.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>intervalMs</code></td><td>The update interval in milliseconds. Invalid values fall back to the default. Default 1000.</td><td>integer</td></tr></tbody></table>

#### Output

Returns nothing.

#### Example

Emit a `tick` event every half second.

```yaml
# intervalMs
500
```

## Event listeners

These functions let you subscribe callbacks to the stopwatch instance events.

### `onStart`

Subscribes to the `start` event. The callback runs whenever you start the stopwatch.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>callback</code></td><td>The callback function.<br>Payload: the current elapsed time in milliseconds.</td><td>callback</td></tr></tbody></table>

#### Output

Returns the string `subscribed`.

### `onStop`

Subscribes to the `stop` event. The callback runs whenever you stop the stopwatch.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>callback</code></td><td>The callback function.<br>Payload: the final elapsed time in milliseconds.</td><td>callback</td></tr></tbody></table>

#### Output

Returns the string `subscribed`.

### `onReset`

Subscribes to the `reset` event. The callback runs whenever you reset the stopwatch.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>callback</code></td><td>The callback function.<br>Payload: none.</td><td>callback</td></tr></tbody></table>

#### Output

Returns the string `subscribed`.

### `onTick`

Subscribes to the `tick` event. This event fires repeatedly at the set interval while the stopwatch is running.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>callback</code></td><td>The callback function.<br>Payload: the current elapsed time in milliseconds.</td><td>callback</td></tr></tbody></table>

#### Output

Returns the string `subscribed`.

### `onLap`

Subscribes to the `lap` event. This event fires when you record a new lap.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>callback</code></td><td>The callback function.<br>Payload: the current lap time in milliseconds and an array of all lap times.</td><td>callback</td></tr></tbody></table>

#### Output

Returns the string `subscribed`.

### `removeAllListeners`

Unsubscribes all active listeners from this stopwatch instance.

#### Parameters

None.

#### Output

Returns the string `unsubscribed`.


# Timer

The timer class introduces countdowns into your flows, maps countdown progress to a custom range, and reacts to ticks and finished countdowns. It also provides a static utility function to format human-readable relative time differences. This class requires an instance for countdown features. The code class name is `Timer`.

## Static functions

Use these functions without creating an instance.

### `getRelativeTime`

Calculates a human-readable, relative time string between a specified time and the current moment (for example, "3 hours ago" or "in 2 years").

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>time</code></td><td></td><td>The time input, either as a Unix timestamp in milliseconds or an ISO 8601 date string.</td><td>any</td></tr><tr><td><code>options</code></td><td><code>locale</code></td><td>The locale code to use for formatting (for example, <code>en</code> or <code>de</code>). Default <code>en</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns the relative time as a string.

#### Examples

**Past time**

Formats an ISO date string.

```yaml
# time
2025-07-12T08:00:00.000Z
# options
locale: en
```

The output depends on the current time, for example `3 hours ago`.

**Future time**

Formats a Unix timestamp in milliseconds.

```yaml
# time
1783903200000
```

The output depends on the current time, for example `in 2 years`.

## Instance functions

You must create an instance to use these functions.

### `create`

Creates a new timer instance with a configured duration and progress range.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>min</code></td><td>The value representing the start of the timer progress. Default 0.</td><td>integer</td></tr><tr><td></td><td><code>max</code></td><td>The value representing the end of the timer progress. Default 100.</td><td>integer</td></tr><tr><td></td><td><code>totalSeconds</code></td><td>The total duration of the countdown in seconds. Default 10.</td><td>integer</td></tr><tr><td></td><td><code>autoStop</code></td><td>Automatically stops the timer when it reaches zero. If <code>false</code>, the timer keeps running and its state becomes <code>overdue</code>. Default <code>true</code>.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns the name of the created instance.

#### Example

```yaml
# options
totalSeconds: 60
min: 0
max: 100
```

### `delete`

Deletes a timer instance.

#### Parameters

None.

#### Output

Returns `true` upon removal.

{% hint style="danger" %}

#### Irreversible action

Deleting removes the instance configuration.
{% endhint %}

### `setTotalSeconds`

Sets the total duration of the timer.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>seconds</code></td><td>The total number of seconds for the countdown.</td><td>integer</td></tr></tbody></table>

#### Output

Returns nothing.

### `getTotalSeconds`

Returns the total duration of the timer in seconds.

#### Parameters

None.

#### Output

Returns the total seconds as an integer.

### `getSecondsLeft`

Returns the remaining seconds on the timer. When the timer is stopped, this returns the total seconds configuration.

#### Parameters

None.

#### Output

Returns the seconds left as an integer.

### `getProgress`

Returns the current progress of the timer, mapped to the defined `min` and `max` range. When the timer is stopped, this returns the `min` value.

#### Parameters

None.

#### Output

Returns the progress value as an integer.

### `getState`

Returns the current state of the timer.

#### Parameters

None.

#### Output

Returns a string representing the state: `stopped`, `started`, or `overdue`.

### `start`

Starts the countdown timer and sets the remaining time to the configured total. If called while a delayed stop is pending, this action only cancels the stop command.

#### Parameters

None.

#### Output

Returns nothing. If the timer is already started, the function returns the difference between remaining and total seconds.

### `stop`

Stops the timer.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>waitingPeriod</code></td><td>An optional delay in milliseconds before the timer stops. If you call <code>start</code> during this period, the stop command is cancelled. Subsequent <code>stop</code> calls during this period are ignored. Default 0.</td><td>integer</td></tr></tbody></table>

#### Output

Returns nothing.

#### Example

**Delayed stop**

Stops the timer after a 5-second delay.

```yaml
# waitingPeriod
5000
```

## Event listeners

These functions let you subscribe callbacks to the timer instance events.

### `onTick`

Subscribes to the tick event. The callback runs every second while the timer is running.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>callback</code></td><td>The callback function.<br>Payload: <code>secondsLeft</code> (integer) and <code>currentProgress</code> (integer).</td><td>callback</td></tr></tbody></table>

#### Output

Returns the string `subscribed`.

#### Example

```yaml
# callback
<callback>
```

### `onTimeup`

Subscribes to the timeup event. The callback runs once when the countdown reaches zero.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>callback</code></td><td>The callback function.<br>Payload: the Unix timestamp in milliseconds when the countdown finished.</td><td>callback</td></tr></tbody></table>

#### Output

Returns the string `subscribed`.

#### Example

```yaml
# callback
<callback>
```


# Users

The users class manages users and App access programmatically. Use it to list available Apps, look up specific Apps, view registered users, and generate invitation links to onboard users dynamically. This class provides static functions only and does not require an instance. The code class name is `Users`.

### `getApplications`

Retrieves a list of all available Apps. Use this function to get an overview or populate selection lists in your UI.

#### Parameters

None.

#### Output

Returns an array of App objects, each containing `id` and the App's data fields such as `appName` and `appId`. Throws an error if the request fails.

### `getApplication`

Retrieves details for a specific App.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>app</code></td><td>The name, short ID, or long ID (UUID) of the App.</td><td>string</td></tr></tbody></table>

#### Output

Returns a single App object, or nothing if not found.

#### Examples

```yaml
# app
My Dashboard App
```

### `getUsers`

Retrieves a list of all users registered for a specific App.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>app</code></td><td>The name, short ID, or long ID (UUID) of the App.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of user objects containing profile and status details. Returns an empty array if the App is not found. `lastLogin` is a Unix timestamp in milliseconds.

```json
[
  {
    "email": "jane.doe@company.com",
    "username": "jdoe",
    "firstName": "Jane",
    "lastName": "Doe",
    "userId": "a1b2c3...",
    "picture": "https://...",
    "authenticationToken": "kY7x...",
    "roles": ["admin"],
    "lastLogin": 1678886400000,
    "active": true,
    "verified": true
  },
  {
    "email": "john.smith@company.com",
    "firstName": "John",
    "userId": "d4e5f6...",
    "roles": [],
    "active": true,
    "verified": false
  }
]
```

#### Examples

```yaml
# app
Shopfloor Monitor
```

### `createAccessLink`

Generates a link for a user to access a specific App. The function automatically handles three scenarios:

1. **New user:** If the email address does not exist, the function creates the user and generates an invite link.
2. **Existing user without a password:** If the user exists but has not set a password, the function generates an invite link prompting them to set one.
3. **Existing active user:** If the user exists and has a valid password, the function generates a standard login link.

Use this function to build user invitation features in your Apps.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>app</code></td><td>The name, short ID, or long ID (UUID) of the target App.</td><td>string</td></tr><tr><td><code>email</code></td><td>The email address of the user.</td><td>string</td></tr></tbody></table>

#### Output

Returns an object containing the generated link and user status details. Throws an error if the App is not found.

* `link`: The invite or standard login link to send to the user depending on their scenario.
* `login`: The standard login link for the App.
* `userStatus`: Returns `created` if a new user was created, or `existed` if they already had an account.
* `registrationStatus`: Returns `created` if the user was newly registered for this App, or `existed`.
* `passwordSetupRequired`: Returns `true` if the user must set a password using the invite link.

```json
{
  "link": "https://acme.heisenware.cloud/app/acme.default/387c2.../invite/?changePasswordId=...",
  "login": "https://acme.heisenware.cloud/app/acme.default/387c2...",
  "userStatus": "created",
  "registrationStatus": "created",
  "passwordSetupRequired": true
}
```

#### Examples

```yaml
# app
My Dashboard App
# email
new.employee@company.com
```


# Subflows

A subflow bundles multiple functions into a single, reusable custom function. You define which inputs go in and which output comes out. On the canvas, the subflow behaves like any other function: it has inputs, a trigger, and an output, and you wire it into your flows the same way.

Use subflows to:

* Reuse logic you need in several places instead of copying functions.
* Keep the canvas clean by hiding implementation details behind one block.
* Share a tested algorithm as a single building block.

### Creating a subflow

{% stepper %}
{% step %}
**Add a subflow**

Drag a subflow from the toolbar onto the canvas. A named container appears, marked with a subflow label.
{% endstep %}

{% step %}
**Add your logic**

Add the functions that make up your logic to the container, just like adding functions to a group.
{% endstep %}

{% step %}
**Define the interface**

Connect your logic to the input, trigger, and output of the orange function block inside the container. This block defines the interface of your new custom function.
{% endstep %}
{% endstepper %}

### Naming a subflow

Every subflow gets a default name (e.g. run\_aa7L). Edit the title of the container to rename it. The name updates in the Function Explorer accordingly.

### Using a subflow

Once created, your custom function appears in the Function Explorer under Custom > Subflows. From there, drag it onto the canvas and use it like any built-in function.

### Subflows vs. grouping

A group is a visual aid only and has no effect on execution. A subflow is a functional unit with a defined interface. Use groups to tidy up, use subflows to build reusable logic.


# Docker Extensions

Docker Extensions expand platform capabilities using Docker container technology. A Docker Extension is a standard Docker image that the platform loads, executes, and exposes as functions inside the App Builder.

{% hint style="info" %}

#### Docker Extensions versus extension nodes

Docker Extensions add completely new function classes to the platform. Do not confuse them with [extension nodes](/app-builder/build-backend/extension-nodes) (modifiers, filters, recorders, and error handlers), which are the small nodes that attach directly to a function output on the canvas.
{% endhint %}

The platform supports two categories of Docker Extensions:

1. **Official extensions**: Pre-built, managed modules maintained by Heisenware.
2. **Custom Extensions**: User-created Docker images containing custom algorithms, drivers, or proprietary logic.

## Official extensions

Pre-built modules add advanced capabilities to the platform without manual coding:

<table><thead><tr><th width="220">Extension</th><th>Description</th></tr></thead><tbody><tr><td><a href="/pages/UEZ2OLoub8DQ4SLIJRP9">Industrial blockchain</a></td><td>Provides immutable data logging and audit trails.</td></tr><tr><td><a href="/pages/gPRuYdWMIpqkpPErq8LX">RAG AI</a></td><td>Enables Retrieval-Augmented Generation for context-aware AI assistants.</td></tr><tr><td><a href="/pages/uuG7Fipc2p1UTkv1svNn">Process simulations</a></td><td>Simulates utilities consumption, CNC machine telemetry, and silo fill levels.</td></tr><tr><td><a href="/pages/DKRT9cAm6tafK1vesdkv">OGC SensorThings API</a></td><td>Manages IoT sensor data via the standardized OGC SensorThings specification.</td></tr></tbody></table>

Once installed, these extensions run alongside standard platform services, appearing as selectable blocks in the Function Explorer.

<div align="left"><figure><img src="/files/b83grU7wYOy0Th9Wac5f" alt="" width="485"><figcaption><p>Adding extensions to the App Builder</p></figcaption></figure></div>

## Custom Extensions

Build a custom Docker Extension by wrapping code inside a Code Adapter and loading the image into the platform or running it on your infrastructure. See the [Custom Extensions](/app-builder/build-backend/functions/extensions/custom-extensions) guide for deployment steps.


# Custom Extensions

Custom Extensions let you extend the Heisenware platform to your specific needs. We provide a project setup into which you add your custom functionality in a completely non-intrusive fashion. Built on our [VRPC](/advanced/vrpc) library, you write plain Node.js code (no APIs to learn) and make it ready for visual programming in minutes.

{% hint style="info" %}
We are actively working on the same idea for C++ and Python.
{% endhint %}

The best starting point is our [docker-extension-starter-js](https://github.com/heisenware/heisenware-docker-extension-starter-js). We recommend [downloading this project](https://github.com/heisenware/heisenware-docker-extension-starter-js/archive/refs/heads/master.zip) as a scaffold, changing it to your needs, and placing it under your version control.

You end up creating a Docker image whose containers integrate into the platform in one of two ways.

## Running inside the platform

Once your Docker image is built, pushed, and publicly accessible ([contact us](mailto:support@heisenware.com) for private registry support), load it as a Custom Extension.

<div align="left"><figure><img src="/files/riPUYu27g4hQUeEYqQML" alt=""><figcaption></figcaption></figure></div>

Once installed, and given your code is syntactically correct, it immediately appears in the [Function Explorer](/app-builder/build-backend/functions/function-explorer). To apply a new version, install it again (works even with the same label).

{% hint style="info" %}
Any instances you create are automatically persisted and restarted. You find them in the [File Explorer](/app-builder/build-backend/file-explorer) under `extensions/my-extension/...`
{% endhint %}

## Running outside the platform

This lets you run your custom code on-premises while we bridge it automatically, seamlessly, and securely into the cloud. Start a container of your image locally and configure it with the correct credentials using environment variables:

```bash
docker run -it \
-e HW_DOMAIN=<account>.<workspace> \
-e HW_BROKER=mqtts://<account>.heisenware.cloud \
-e HW_USERNAME=<username> \
-e HW_PASSWORD=<password> \
myusername/myimage:1.0.0
```

To retrieve a valid username and password, add a VRPC integration under [Integrations (inbound)](/app-manager/inbound-integrations) in the App Manager.

Example: For an account named `my-company`, an integration with username `agentRunner`, and a password `secret`, the call would be:

```bash
docker run -it \
-e HW_DOMAIN=my-company.default \
-e HW_BROKER=mqtts://my-company.heisenware.cloud \
-e HW_USERNAME=agentRunner \
-e HW_PASSWORD=secret \
myusername/myimage:1.0.0
```

When everything is set up correctly, you should see something like this on your console:

<figure><img src="/files/6LXA4JlKYHIfLkTct99b" alt=""><figcaption></figcaption></figure>


# Industrial Blockchain

The industrial blockchain extension provides an interface to interact with a SafeUrChain blockchain node. This specialized ledger creates a secure, immutable record for tracking data across manufacturing and supply chain networks.

Use this class to manage the node lifecycle, execute transaction writes, and query the ledger. This class requires an instance for ledger operations, but provides static functions for node process management. The code class name is `SafeUrChain`.

## Node management

Use these static functions to control the local blockchain node process.

### `startNode`

Starts a SafeUrChain node on the local system.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>network</code></td><td>The name of the network to join. Default <code>'hsmw'</code>.</td><td>string</td></tr><tr><td></td><td><code>index</code></td><td>A unique identification index for this node in the network. Default 0.</td><td>integer</td></tr><tr><td></td><td><code>validator</code></td><td>Enables participation in block validation and creation. Default <code>true</code>.</td><td>boolean</td></tr><tr><td></td><td><code>validators</code></td><td>An array of trusted validator node IDs.</td><td>array</td></tr><tr><td></td><td><code>storeTransactionsFrom</code></td><td>An array of node ID patterns from which to store transactions.</td><td>array</td></tr><tr><td></td><td><code>singleNode</code></td><td>Runs the node in standalone isolation mode. Default <code>true</code>.</td><td>boolean</td></tr><tr><td></td><td><code>blockTimeInMs</code></td><td>The target duration between block creations in milliseconds. Default 5000.</td><td>integer</td></tr></tbody></table>

#### Output

Returns nothing.

#### Examples

**Start a single validator node**

Configures and starts a standalone test network node.

```yaml
# options
network: local-test
index: 0
validator: true
validators: ['local-test-0']
singleNode: true
```

### `stopNode`

Stops the currently running node process.

#### Parameters

None.

#### Output

Returns nothing.

### `isNodeRunning`

Checks whether the node process is active on the system.

#### Parameters

None.

#### Output

Returns `true` if the node runs, or `false` if it is stopped.

### `create`

Initializes a new SafeUrChain API client instance connected to a specific node's GraphQL endpoint.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>apiUrl</code></td><td>The endpoint URL of the SafeUrChain node API. Falls back to internal environment variables if omitted.</td><td>string</td></tr></tbody></table>

#### Output

Returns the API client instance.

#### Examples

```yaml
# apiUrl
http://localhost:7878
```

## Writing and reading data

Use these member functions to interact with the ledger.

### `write`

Writes a data point as a new transaction to the blockchain. The ledger timestamps the entry and indexes it under a designated measurement string.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>measurement</code></td><td>The category identifier for the recorded data.</td><td>string</td></tr><tr><td><code>data</code></td><td>The data payload to record. Accepts any JSON-serializable value.</td><td>any</td></tr><tr><td><code>tags</code></td><td>Optional key-value metadata pairs used for filtering queries.</td><td>object</td></tr></tbody></table>

#### Output

Returns a string containing the unique transaction hash.

#### Examples

**Record a temperature reading**

```yaml
# measurement
temperature
# data
25.5
# tags
machineId: M-500
unit: celsius
```

### `read`

Queries data from the blockchain by measurement category and filters the results using metadata tags.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>measurement</code></td><td></td><td>The name of the measurement category to query.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>tags</code></td><td>Key-value pairs to filter records. Matches entries containing all specified tags.</td><td>object</td></tr></tbody></table>

#### Output

Returns an array of data point objects sorted chronologically by date. Each object includes the value, timestamp, transaction hash, and block height.

#### Examples

**Query machine logs**

```yaml
# measurement
temperature
# options
tags:
  machineId: M-500
```

### `getDataPoint`

Retrieves a single data point directly using its unique transaction hash.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>transactionHash</code></td><td>The targeted unique transaction hash identifier.</td><td>string</td></tr></tbody></table>

#### Output

Returns an object containing the stored payload value, timestamp, block hash, and block height.

## Blockchain inspection

Use these functions to monitor blockchain structure and health status.

### `getTopBlock`

Retrieves the latest block added to the chain.

#### Parameters

None.

#### Output

Returns an object containing the block digest hash and header info (including height, timestamp, and previous digest hash).

### `getBlockAtHeight`

Retrieves a specific block using its sequential block height number.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>height</code></td><td>The block sequence number.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the block object details.

### `getBlocks`

Retrieves a sequence range of blocks.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>from</code></td><td>The starting sequential block height.</td><td>integer</td></tr><tr><td><code>to</code></td><td>The ending sequential block height.</td><td>integer</td></tr></tbody></table>

#### Output

Returns an array of block objects.

### `getHashesInBlock`

Retrieves all transaction hashes wrapped inside a specific block.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>block</code></td><td>The target block digest hash string.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of transaction hash strings.

### `getTelemetry`

Retrieves network health information, node connection statuses, and active peer details.

#### Parameters

None.

#### Output

Returns a network telemetry status object.


# RAG AI

Retrieval-Augmented Generation (RAG) pairs a prompt with relevant content retrieved from a local vector knowledge store. Answers are grounded in your own documents and manuals, which reduces hallucinations.

{% hint style="info" %}

#### Environment configuration requirement

Provide a valid `OPENAI_API_KEY` as environment parameter when launching this module.

<img src="/files/1ciU4mj2k5yo5Y0XvUH9" alt="" data-size="original">
{% endhint %}

The RAG AI extension bundles two classes: `KnowledgeBase` and `ChatWithData`. You first populate a knowledge store using `KnowledgeBase`, then a `ChatWithData` instance uses that store to answer questions.

## Knowledge base

The `KnowledgeBase` class creates, manages, and queries vectorized knowledge stores. It ingests information from various sources (files, URLs, text), splits it into searchable chunks, creates vector embeddings, and stores them in a vector database (ChromaDB). This class provides static functions only and does not require an instance. The code class name is `KnowledgeBase`.

### `addKnowledge`

Adds information from a source into a specific knowledge store. The function automatically detects the source type, processes the content, splits it into chunks, creates vector embeddings, and stores them.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="140">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>store</code></td><td></td><td>The name of the knowledge store, for example <code>product-manuals</code>.</td><td>string</td></tr><tr><td><code>knowledge</code></td><td></td><td>The content to add. Accepts a URL string, a local file path string (supported extensions: <code>pdf</code>, <code>txt</code>, <code>csv</code>, <code>docx</code>, <code>pptx</code>, <code>html</code>), a plain text string, or a JSON object.</td><td>any</td></tr><tr><td><code>name</code></td><td></td><td>A name identifying this knowledge source, used for later management (for example <code>Product Manual v2</code>).</td><td>string</td></tr><tr><td><code>options</code></td><td><code>chunkSize</code></td><td>The maximum size of each text chunk. Default 2000.</td><td>integer</td></tr><tr><td></td><td><code>chunkOverlap</code></td><td>The number of characters to overlap between chunks. Default 400.</td><td>integer</td></tr></tbody></table>

#### Output

Returns `true` once the knowledge has been added.

#### Examples

**Adding knowledge from a PDF file**

```yaml
# store
product-manuals

# knowledge
/path/to/files/ATR7000-manual.pdf

# name
ATR7000 Manual
```

**Adding knowledge from a website**

```yaml
# store
company-info

# knowledge
https://heisenware.com/about-us

# name
About Heisenware
```

**Adding knowledge from a plain text string**

```yaml
# store
faq

# knowledge
'Question: What are the support hours? Answer: Support is available 24/7 via email.'

# name
Support Hours FAQ
```

### `similaritySearch`

Performs a similarity search against a knowledge store to find the text chunks most relevant to a given query.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>store</code></td><td>The name of the knowledge store.</td><td>string</td></tr><tr><td><code>query</code></td><td>The text query to search for.</td><td>string</td></tr><tr><td><code>nDocs</code></td><td>The maximum number of relevant chunks to return.</td><td>integer</td></tr></tbody></table>

#### Output

Returns an array of document objects relevant to the query.

### `getDocuments`

Lists all named documents currently stored in a knowledge store.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>store</code></td><td>The name of the knowledge store.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array of objects, one per added document source.

### `deleteDocument`

Deletes all chunks associated with a specific named document from the knowledge store.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>store</code></td><td>The name of the knowledge store.</td><td>string</td></tr><tr><td><code>name</code></td><td>The name of the document source to delete (the same name provided in <code>addKnowledge</code>).</td><td>string</td></tr></tbody></table>

{% hint style="danger" %}

#### Irreversible action

Deleting permanently removes all chunks of the document from the store.
{% endhint %}

### `getMetaData`

Retrieves detailed metadata for all chunks stored in a knowledge store, useful for debugging.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="140">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>store</code></td><td></td><td>The name of the knowledge store.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>showData</code></td><td>If <code>true</code>, includes the raw text content of each chunk. Default <code>false</code>.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns the metadata for all chunks stored in the knowledge store.

### `reset`

Completely deletes all information in a given knowledge store.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>store</code></td><td>The name of the knowledge store to reset.</td><td>string</td></tr></tbody></table>

{% hint style="danger" %}

#### Irreversible action

Resetting permanently deletes all information in the store.
{% endhint %}

## Chat with data

The `ChatWithData` class creates a conversational AI (chatbot) that answers questions based on the information held in a specific `KnowledgeBase` store. When you ask a question, it first searches the knowledge store for relevant information using [`similaritySearch`](#similaritysearch). It then combines your question, the chat history, and the retrieved context into a new prompt that it sends to an OpenAI model to generate a well-informed answer. This class requires an instance. The code class name is `ChatWithData`.

### `create`

Creates a chat instance linked to a specific knowledge store and configured with the desired AI behavior.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="140">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>storeName</code></td><td></td><td>The name of the <code>KnowledgeBase</code> store this chat instance will use.</td><td>string</td></tr><tr><td><code>options</code></td><td><code>openAIApiKey</code></td><td>Your OpenAI API key.</td><td>string</td></tr><tr><td></td><td><code>temperature</code></td><td>The model's creativity level, a value from 0 to 1. Default 0.1.</td><td>number</td></tr><tr><td></td><td><code>modelName</code></td><td>The OpenAI model to use, for example <code>gpt-4</code>.</td><td>string</td></tr><tr><td></td><td><code>systemMessage</code></td><td>A general instruction telling the chatbot how to behave.</td><td>string</td></tr><tr><td></td><td><code>nDocuments</code></td><td>The maximum number of documents to retrieve from the knowledge store for context. Default 4.</td><td>integer</td></tr></tbody></table>

{% hint style="info" %}

#### Mark the API key as a secret

Right-click the input carrying the API key and mark it as a secret.
{% endhint %}

#### Output

Returns the name of the created instance.

#### Example

```yaml
# storeName
product-manuals

# options
temperature: 0.2
systemMessage: You are an expert on our products. Answer questions based on the provided manuals.
```

### `delete`

Deletes a chat instance.

#### Parameters

None.

#### Output

Returns `true` upon removal.

{% hint style="danger" %}

#### Irreversible action

Deleting removes the instance configuration. The underlying knowledge store remains unchanged.
{% endhint %}

### `executePrompt`

Sends a question to the chatbot and gets an answer. This is the primary function for interacting with the chat instance.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>question</code></td><td>The user's question or prompt.</td><td>string</td></tr></tbody></table>

#### Output

Returns an object with the keys `answer` (the response string), `history` (the updated conversation history), `sourceDocs` (an array of the source document chunks used to generate the answer), and `tokenUsage` (information about the number of tokens used for the request).

### `addKnowledge`

Adds new information to the knowledge store associated with this chat instance. This is a convenience wrapper around [`addKnowledge`](#addknowledge) of the `KnowledgeBase` class.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>knowledge</code></td><td>The content to add. Accepts the same source types as the <code>KnowledgeBase</code> function.</td><td>any</td></tr></tbody></table>

### `resetConversion`

Clears the current conversation history. The chatbot forgets the previous conversation, but the underlying knowledge store remains unchanged.

#### Parameters

None.

### `reinitialize`

Reinitializes the chat instance with new configuration options.

## Complete example

A step-by-step workflow demonstrating how the two classes work together.

{% stepper %}
{% step %}

#### Populate a knowledge store

Use `addKnowledge` of the `KnowledgeBase` class to add information to a store.

```yaml
# store
product-info

# knowledge
/path/to/our-product-spec-sheet.pdf

# name
Spec Sheet v1.2
```

{% endstep %}

{% step %}

#### Create a chat instance

Create a `ChatWithData` instance linked to the store you just populated.

```yaml
# storeName
product-info

# options
systemMessage: You are a helpful product support specialist.
```

{% endstep %}

{% step %}

#### Ask a question

Use `executePrompt` to ask a question related to the document you added.

```yaml
# question
What is the maximum operating temperature of our product?
```

The chatbot finds the relevant section in the PDF, uses it as context, and provides a specific answer.
{% endstep %}

{% step %}

#### Ask a follow-up question

The chatbot remembers the context of the conversation.

```yaml
# question
And what about in Celsius?
```

The chatbot understands that the follow-up refers to the maximum operating temperature and answers in the requested unit.
{% endstep %}
{% endstepper %}


# Process Simulations

The process simulations extension models industrial equipment behaviors, machine profiles, and utilities dynamics. Use these nodes to feed synthetic workflows into data grids, charts, and databases before connecting live physical machinery. This class requires an instance. The code class identifier maps to individual simulator models.

## Energy consumption simulation

The `EnergySimulator` class models continuous household or factory utilities usage (power, gas, and hot water) using cyclical sine wave rhythms combined with dynamic noise variations.

### `create`

Initializes an energy simulator model targeting explicit annual baselines.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>config</code></td><td><code>power</code></td><td>Target annual power consumption in kilowatt-hours (kWh).</td><td>integer</td></tr><tr><td></td><td><code>gas</code></td><td>Target annual gas volume consumption in cubic meters (m³).</td><td>integer</td></tr><tr><td></td><td><code>water</code></td><td>Target annual hot water volume consumption in cubic meters (m³).</td><td>integer</td></tr></tbody></table>

#### Output

Returns the simulation instance. The background loop starts automatically.

#### Examples

```yaml
# config
power: 4500
gas: 1200
water: 90
```

### `start`

Resumes the background calculations updater loop.

#### Parameters

None.

#### Output

Returns `true` when execution resumes.

### `stop`

Freezes current values and pauses the updater background loop.

#### Parameters

None.

#### Output

Returns `true` when execution pauses.

### `getLiveValue`

Returns the instantaneous usage rate for a chosen media utility.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>mediaType</code></td><td>The targeted utility name. Must be <code>power</code>, <code>gas</code>, or <code>water</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns a number representing the immediate consumption rate:

* **Power**: Kilowatts (kW)
* **Gas**: Cubic meters per hour (m³/h)
* **Water**: Cubic meters per hour (m³/h)

#### Examples

```yaml
# mediaType
power
```

### `getAggregatedValue`

Returns the total accumulated consumption volume logged since instance launch.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>mediaType</code></td><td>The targeted utility name. Must be <code>power</code>, <code>gas</code>, or <code>water</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns a number tracking cumulative metrics:

* **Power**: Kilowatt-hours (kWh)
* **Gas**: Cubic meters (m³)
* **Water**: Cubic meters (m³)

## Machine simulation

The `MachineSimulator` class reproduces a standard CNC milling station, fluctuating real-time operational telemetry (including speed, load, and internal temperatures) while processing order backlogs.

### `create`

Constructs a simulated CNC equipment identity profile.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>config</code></td><td><code>id</code></td><td>Unique serial or station string ID.</td><td>string</td></tr><tr><td></td><td><code>name</code></td><td>Human-readable display name string.</td><td>string</td></tr><tr><td></td><td><code>model</code></td><td>Equipment model designation. Default <code>Generic-CNC</code>.</td><td>string</td></tr></tbody></table>

#### Output

Returns the machine simulation instance.

#### Examples

```yaml
# config
id: cnc-042
name: 5-Axis Miller
model: Mazak-X5
```

### `connect`

Spins up internal runtime loops, transitioning device telemetry states from offline baselines into live operational parameters.

#### Parameters

None.

#### Output

Returns `true`.

### `disconnect`

Shuts down active cycles, resetting spindle metrics to zero and cooling temperatures back to room ambient baselines.

#### Parameters

None.

#### Output

Returns `true`.

### `getData`

Returns a unified state record combining active job specifics with raw sensor diagnostics.

#### Parameters

None.

#### Output

Returns a flat payload object tracking running characteristics.

Example payload:

```json
{
  "id": "cnc-042",
  "name": "5-Axis Miller",
  "model": "Mazak-X5",
  "timestamp": "2026-02-19T10:25:14.000Z",
  "status": "RUNNING",
  "spindleSpeed": 11950.4,
  "feedRate": 1495.2,
  "temperature": 64.8,
  "powerLoad": 76.1,
  "currentOrderId": "ORD-8392",
  "operationId": "OP-45",
  "partName": "Flange-X9",
  "targetQuantity": 45,
  "completedQuantity": 12,
  "cycleTime": 4,
  "lastCycleStart": 1708338310000
}
```

## Silo fill level simulation

The `SiloSimulator` class outputs an ongoing depletion lifecycle. Material content gradually drains until crossing a low 10% safety threshold, automatically engaging a rapid recharge process.

### `create`

Defines physical volume boundaries and consumption speeds.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="120">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>capacity</code></td><td>The maximum structural mass or volume capacity. Default 100.</td><td>integer</td></tr><tr><td></td><td><code>timeToEmpty</code></td><td>Duration in seconds required to deplete content from full capacity down to the 10% target threshold. Default 60.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the silo simulation instance.

#### Examples

```yaml
# options
capacity: 500
timeToEmpty: 300
```

### `start`

Engages depletion cycles and kicks off regular telemetry broadcasts.

### `stop`

Halts processing routines.

### `getLevel`

Returns the immediate quantitative volume level state manually.

#### Output

Returns the level metric as an integer or float.

### `onLevelUpdate`

Fires update events repeatedly every second during active operations.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>callback</code></td><td>The callback function.<br>Payload: current volume level.</td><td>callback</td></tr></tbody></table>

#### Output

Returns nothing.


# OGC SensorThings API

{% hint style="info" %}

#### Available as a Docker Extension

This connector is not part of the default function list. It ships as a [Docker Extension](/app-builder/build-backend/functions/extensions), where the installation is explained.
{% endhint %}

The OGC SensorThings API connector talks to an OGC SensorThings compliant server (such as a FROST server) and manages Things, Locations, ObservedProperties, Sensors, Datastreams, and Observations. This class requires an instance. The code class name is `SensorThings`.

## Example use case

Imagine an environmental monitoring application that collects data from various sensors deployed in a city. Using the OGC SensorThings API, the application:

* retrieves current air quality indexes from different areas within the city
* gathers temperature and humidity readings to monitor weather conditions
* accesses noise level data to identify noise pollution hotspots

## General conventions

* All IDs refer to the `@iot.id` property of SensorThings resources.
* All date and time values follow ISO 8601.
* For geospatial data in Locations, GeoJSON is recommended (`encodingType: 'application/geo+json'`).

{% hint style="danger" %}

#### Irreversible action

All delete functions (`deleteThing`, `deleteLocation`, `deleteObservedProperty`, `deleteSensor`, `deleteDatastream`, `deleteObservation`) permanently remove the resource from the server.
{% endhint %}

## Filter expressions

All `get*` list functions accept an optional OGC compliant [filter expression](https://fraunhoferiosb.github.io/FROST-Server/sensorthingsapi/requestingData/STA-Example-Queries.html), such as:

```
name eq 'StationA'
description ne 'Old station'
properties/owner eq 'City Council'
```

## Instance management

### `create`

Creates a SensorThings client instance.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>apiUrl</code></td><td>The URL of the SensorThings server, for example <code>https://server.de/FROST-Server/v1.1</code>. If omitted, the internal FROST server is used.</td><td>string</td></tr></tbody></table>

#### Output

Returns the name of the created instance.

### `delete`

Deletes a client instance.

#### Parameters

None.

#### Output

Returns `true` upon removal.

{% hint style="danger" %}

#### Irreversible action

Deleting removes the instance configuration.
{% endhint %}

## Things

### `createThing`

Creates a Thing, an object of the physical or information world that can be identified and integrated into communication networks.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="140">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>name</code></td><td>Name of the Thing.</td><td>string</td></tr><tr><td></td><td><code>description</code></td><td>Description of the Thing. Default empty.</td><td>string</td></tr><tr><td></td><td><code>properties</code></td><td>Any further properties of the Thing. Default <code>{}</code>.</td><td>object</td></tr><tr><td></td><td><code>uniqueName</code></td><td>If <code>true</code>, an existing Thing with the same name is updated instead of creating a duplicate. Default <code>false</code>.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns the numeric ID of the created Thing. If `uniqueName` is set and a Thing with the same name exists, that Thing is updated and the server answer of the update is returned instead.

### `getThings`

Retrieves all or a filtered set of Things.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filter</code></td><td>Optional filter expression, see <a href="#filter-expressions">Filter expressions</a>.</td><td>string</td></tr></tbody></table>

#### Output

Returns the server result object with a `value` array of Things. Locations are expanded.

### `getThing`

Reads all information of a single Thing.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Thing ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the Thing object with expanded Locations and HistoricalLocations.

### `updateThing`

Updates a Thing.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Thing ID.</td><td>integer</td></tr><tr><td><code>changes</code></td><td>An object containing only the fields to change, for example <code>name</code>, <code>description</code>, or <code>properties</code>.</td><td>object</td></tr></tbody></table>

#### Output

Returns the server answer to the update request.

### `deleteThing`

Deletes a Thing.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Thing ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the server answer to the delete request.

### `linkLocations`

Links Locations to a Thing.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>thingId</code></td><td>The Thing ID.</td><td>integer</td></tr><tr><td><code>locationIds</code></td><td>Array of Location IDs to link.</td><td>array</td></tr></tbody></table>

#### Output

Returns nothing. The update runs without waiting for the server, so errors are not reported back.

### `unlinkAllLocations`

Removes all Location links from a Thing.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>thingId</code></td><td>The Thing ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the server answer to the update request.

## Locations

### `createLocation`

Creates a Location. The Location locates the Thing or Things it is associated with; a Thing's Location is defined as its last known location.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="140">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>name</code></td><td>Name of the Location.</td><td>string</td></tr><tr><td></td><td><code>location</code></td><td>Location data in the format defined by <code>encodingType</code>, typically a GeoJSON object.</td><td>any</td></tr><tr><td></td><td><code>description</code></td><td>Description of the Location. Default empty.</td><td>string</td></tr><tr><td></td><td><code>properties</code></td><td>Any further properties of the Location. Default <code>{}</code>.</td><td>object</td></tr><tr><td></td><td><code>encodingType</code></td><td>Encoding type of the location data. Default <code>application/geo+json</code>.</td><td>string</td></tr><tr><td></td><td><code>uniqueName</code></td><td>If <code>true</code>, an existing Location with the same name is updated instead of creating a duplicate. Default <code>false</code>.</td><td>boolean</td></tr><tr><td><code>thingIds</code></td><td></td><td>Array of Thing IDs to link the Location to. Default <code>[]</code>.</td><td>array</td></tr></tbody></table>

#### Output

Returns the numeric ID of the created Location. If `uniqueName` is set and a Location with the same name exists, that Location is updated and its ID is returned.

#### Example

```yaml
# options
name: Warehouse A
description: Main storage site
location:
  type: Point
  coordinates: [9.99, 53.55]

# thingIds
[12, 13]
```

### `getLocations`

Retrieves all or a filtered set of Locations.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filter</code></td><td>Optional filter expression, see <a href="#filter-expressions">Filter expressions</a>.</td><td>string</td></tr></tbody></table>

#### Output

Returns the server result object with a `value` array of Locations. Things are expanded.

### `getLocation`

Retrieves a single Location.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Location ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the Location object with expanded Things.

### `updateLocation`

Updates a Location.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Location ID.</td><td>integer</td></tr><tr><td><code>changes</code></td><td>An object containing only the fields to change, for example <code>name</code>, <code>description</code>, <code>properties</code>, <code>location</code>, or <code>encodingType</code>.</td><td>object</td></tr></tbody></table>

#### Output

Returns the server answer to the update request.

### `deleteLocation`

Deletes a Location.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Location ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the server answer to the delete request.

### `showLocationHistory`

Aggregates the historical Locations of a Thing by time and a selected property.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>thingId</code></td><td>The Thing ID.</td><td>integer</td></tr><tr><td><code>property</code></td><td>A key found in the <code>properties</code> section of each Location.</td><td>string</td></tr></tbody></table>

#### Output

Returns an array with one entry per historical location record, each containing a `time` string (minute resolution) and one key per Location name holding the value of the selected property.

## Observed properties

### `createObservedProperty`

Creates an ObservedProperty, which specifies the phenomenon of an Observation.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="140">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>name</code></td><td>Name of the ObservedProperty.</td><td>string</td></tr><tr><td></td><td><code>description</code></td><td>Description of the ObservedProperty. Default empty.</td><td>string</td></tr><tr><td></td><td><code>properties</code></td><td>Any further properties. Default <code>{}</code>.</td><td>object</td></tr><tr><td></td><td><code>definition</code></td><td>URI of a controlled vocabulary term. Default empty.</td><td>string</td></tr><tr><td></td><td><code>uniqueName</code></td><td>If <code>true</code>, an existing ObservedProperty with the same name is updated instead of creating a duplicate. Default <code>false</code>.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns the numeric ID of the created or updated ObservedProperty.

### `getObservedProperties`

Retrieves all or a filtered set of ObservedProperties.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filter</code></td><td>Optional filter expression, see <a href="#filter-expressions">Filter expressions</a>.</td><td>string</td></tr></tbody></table>

#### Output

Returns the server result object with a `value` array of ObservedProperties.

### `getObservedProperty`

Retrieves a single ObservedProperty.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The ObservedProperty ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the ObservedProperty object.

### `updateObservedProperty`

Updates an ObservedProperty.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The ObservedProperty ID.</td><td>integer</td></tr><tr><td><code>changes</code></td><td>An object containing only the fields to change.</td><td>object</td></tr></tbody></table>

#### Output

Returns the server answer to the update request.

### `deleteObservedProperty`

Deletes an ObservedProperty.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The ObservedProperty ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the server answer to the delete request.

## Sensors

### `createSensor`

Creates a Sensor, an instrument that observes a property or phenomenon to estimate its value.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="140">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>name</code></td><td>Name of the Sensor.</td><td>string</td></tr><tr><td></td><td><code>description</code></td><td>Description of the Sensor. Default empty.</td><td>string</td></tr><tr><td></td><td><code>properties</code></td><td>Any further properties. Default <code>{}</code>.</td><td>object</td></tr><tr><td></td><td><code>encodingType</code></td><td>Encoding type of the metadata document, for example <code>application/pdf</code>. Default empty.</td><td>string</td></tr><tr><td></td><td><code>metadata</code></td><td>Metadata URI in the specified encoding type. Default empty.</td><td>string</td></tr><tr><td></td><td><code>uniqueName</code></td><td>If <code>true</code>, an existing Sensor with the same name is updated instead of creating a duplicate. Default <code>false</code>.</td><td>boolean</td></tr></tbody></table>

#### Output

Returns the numeric ID of the created Sensor.

### `getSensors`

Retrieves all or a filtered set of Sensors.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filter</code></td><td>Optional filter expression, see <a href="#filter-expressions">Filter expressions</a>.</td><td>string</td></tr></tbody></table>

#### Output

Returns the server result object with a `value` array of Sensors.

### `getSensor`

Retrieves a single Sensor.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Sensor ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the Sensor object.

### `updateSensor`

Updates a Sensor.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Sensor ID.</td><td>integer</td></tr><tr><td><code>changes</code></td><td>An object containing only the fields to change.</td><td>object</td></tr></tbody></table>

#### Output

Returns the server answer to the update request.

### `deleteSensor`

Deletes a Sensor.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Sensor ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the server answer to the delete request.

## Datastreams

### `createDatastream`

Creates a Datastream, which groups a collection of Observations measuring the same ObservedProperty and produced by the same Sensor.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="180">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>name</code></td><td>Name of the Datastream.</td><td>string</td></tr><tr><td></td><td><code>description</code></td><td>Description of the Datastream. Default empty.</td><td>string</td></tr><tr><td></td><td><code>observationType</code></td><td>URI of the observation type used to encode observations, for example <code>http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement</code>.</td><td>string</td></tr><tr><td></td><td><code>unitOfMeasurement</code></td><td>Object with three keys: <code>name</code> (full name of the unit), <code>symbol</code> (textual form of the unit symbol), and <code>definition</code> (URI defining the unit).</td><td>object</td></tr><tr><td></td><td><code>uniqueName</code></td><td>If <code>true</code>, an existing Datastream with the same name is updated instead of creating a duplicate. Default <code>false</code>.</td><td>boolean</td></tr><tr><td><code>thingId</code></td><td></td><td>A Thing ID to link to.</td><td>integer</td></tr><tr><td><code>sensorId</code></td><td></td><td>A Sensor ID to link to.</td><td>integer</td></tr><tr><td><code>observedPropertyId</code></td><td></td><td>An ObservedProperty ID to link to.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the numeric ID of the created or updated Datastream.

#### Example

```yaml
# options
name: Temperature outdoor
observationType: http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement
unitOfMeasurement:
  name: Degree Celsius
  symbol: °C
  definition: http://unitsofmeasure.org/ucum.html

# thingId
1

# sensorId
2

# observedPropertyId
3
```

### `getDatastreams`

Retrieves all or a filtered set of Datastreams.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filter</code></td><td>Optional filter expression, see <a href="#filter-expressions">Filter expressions</a>.</td><td>string</td></tr></tbody></table>

#### Output

Returns the server result object with a `value` array of Datastreams.

### `getDatastream`

Retrieves a single Datastream.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Datastream ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the Datastream object.

### `updateDatastream`

Updates a Datastream.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Datastream ID.</td><td>integer</td></tr><tr><td><code>changes</code></td><td>An object containing only the fields to change.</td><td>object</td></tr></tbody></table>

#### Output

Returns the server answer to the update request.

### `deleteDatastream`

Deletes a Datastream.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Datastream ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the server answer to the delete request.

## Observations

### `createObservation`

Creates an Observation, the act of measuring or otherwise determining the value of a property.

#### Parameters

<table><thead><tr><th width="150">Input</th><th width="160">Key</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>options</code></td><td><code>result</code></td><td>The measured or estimated value of the observation.</td><td>any</td></tr><tr><td></td><td><code>phenomenonTime</code></td><td>The time instant or period of the observation, in ISO 8601 format.</td><td>string</td></tr><tr><td><code>datastreamId</code></td><td></td><td>A Datastream ID to link to.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the numeric ID of the created Observation.

#### Example

```yaml
# options
result: 21.4
phenomenonTime: 2024-01-01T12:00:00Z

# datastreamId
4
```

### `getObservations`

Retrieves all or a filtered set of Observations, for example with the filter `phenomenonTime ge 2024-01-01T00:00:00Z`.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>filter</code></td><td>Optional filter expression, see <a href="#filter-expressions">Filter expressions</a>.</td><td>string</td></tr></tbody></table>

#### Output

Returns the server result object with a `value` array of Observations.

### `getObservation`

Retrieves a single Observation.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Observation ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the Observation object.

### `updateObservation`

Updates an Observation.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Observation ID.</td><td>integer</td></tr><tr><td><code>changes</code></td><td>An object containing only the fields to change.</td><td>object</td></tr></tbody></table>

#### Output

Returns the server answer to the update request.

### `deleteObservation`

Deletes an Observation.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>id</code></td><td>The Observation ID.</td><td>integer</td></tr></tbody></table>

#### Output

Returns the server answer to the delete request.

## Raw requests

For custom operations, four raw request functions provide direct URL access to the API.

### `getRaw`

Sends a raw GET request.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td>The path or full URL to request.</td><td>string</td></tr></tbody></table>

#### Output

Returns the raw server response.

### `postRaw`

Sends a raw POST request. No request body can be provided.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td>The path or full URL to request.</td><td>string</td></tr></tbody></table>

#### Output

Returns the raw server response.

### `patchRaw`

Sends a raw PATCH request. No request body can be provided.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td>The path or full URL to request.</td><td>string</td></tr></tbody></table>

#### Output

Returns the raw server response.

### `deleteRaw`

Sends a raw DELETE request.

#### Parameters

<table><thead><tr><th width="150">Input</th><th>Description</th><th width="100">Type</th></tr></thead><tbody><tr><td><code>url</code></td><td>The path or full URL to request.</td><td>string</td></tr></tbody></table>

#### Output

Returns the raw server response.

## More information

[OGC SensorThings API Standard 1.0](https://docs.ogc.org/is/15-078r6/15-078r6.html)

[FROST Server Documentation](https://fraunhoferiosb.github.io/FROST-Server/)


# Extension nodes

Extension nodes process data directly within a flow without requiring a full function node. They attach to a function output or to another extension node to act on the data passing through. This lets you build processing pipelines by chaining nodes together, such as connecting a filter to a modifier, or a modifier to another modifier.

Except for recorders, extension nodes operate as their own output. You can wire them to function inputs, triggers, or widgets exactly like a standard function output.

To branch a single data source into multiple concurrent paths, attach multiple extension nodes to the same output in parallel.

## Types

<table><thead><tr><th width="137.0369873046875">Type</th><th>What it does</th></tr></thead><tbody><tr><td><a href="/pages/YtEGKytnifBFufwjxy3Y"><strong>Modifier</strong></a></td><td>Transforms the structure or value of the data, using JSONata or a JavaScript expression.</td></tr><tr><td><a href="/pages/5Q19JgoLcel9vA3B4Kz2"><strong>Filter</strong></a></td><td>Acts as a conditional gate: halts the flow or branches it based on a JavaScript condition.</td></tr><tr><td><a href="/pages/xvLVxy8unY0Xs7VUuENz"><strong>Recorder</strong></a></td><td>Stores the output as timeseries data in the internal InfluxDB database.</td></tr><tr><td><a href="/pages/dWllzGTNSFTFHZAsIHkv"><strong>Error handler</strong></a></td><td>Opens a separate output that activates only when the parent function fails, enabling dedicated error logic. You can only attach an error handler directly to a function, not to other extension nodes.</td></tr></tbody></table>

## Working with extension nodes

* **Add**: Click the + icon on a function's output or on an existing extension node and select the desired type. You can add multiple parallel extension nodes to the same output.
* **Chain**: Add an extension node to the output of another extension node to create a multi-step pipeline (e.g., filter data, then modify it).
* **Test**: Extension nodes show their last result directly below them. Click the icon of a modifier or filter to evaluate it manually during development.
* **Delete**: Right-click an extension node and select Delete.


# Modifier

Modifiers transform data on the fly within a flow. Apply a [JSONata](#jsonata) or [JavaScript expression](#javascript-expressions) to change the structure or value of an output before it reaches the next function, a database, the frontend, or a subsequent extension node (such as another modifier or a filter).

To add a modifier:

1. Click the + icon on the right side of a function output, filter, or existing modifier.
2. Select Modifier from the list.
3. Click the new modifier node (Click to edit...) to open the code editor and write your expression.

A modifier uses either JSONata or a JavaScript expression. Switch between types by right-clicking the modifier and selecting JSONata or Expression. Adjust the default type in the [App Builder settings](/app-builder/overview#app-builder-settings).

Click the modifier icon on the left to evaluate the modifier manually during development. The last result appears below the expression. Right-click also lets you add a comment to the modifier or delete it.

<figure><img src="/files/dQ2Z6Jm4m6Wki8Q1IzJi" alt=""><figcaption><p>A modifier extension node</p></figcaption></figure>

{% hint style="info" %}

#### Need help writing modifiers?

Read how to [use AI for modifiers](#using-ai-for-modifiers) to generate JSONata or JavaScript logic with your favorite chatbot.
{% endhint %}

## JSONata

JSONata is a query and transformation language designed for JSON data. It is the preferred method for structural changes, filtering, and simple math. For a complete guide, see the [official JSONata documentation](https://docs.jsonata.org/overview.html).

* **Reference**: Use the `$` sign to refer to the value from the preceding output.
* **Implicit arguments**: JSONata modifiers automatically process the incoming data if the parentheses are left empty. For example, `$uppercase()` is equivalent to `$uppercase($)`.

### JSONata examples

<details>

<summary><strong>Example 1: Path selection and math</strong></summary>

Extracts a specific nested value from a PLC object and performs a calculation.

Data:

```json
{
  "payload": {
    "sensors": {
      "temp_c": 25
    }
  }
}
```

Modifier content:

```
payload.sensors.temp_c * 1.8 + 32
```

Return of the modifier:

```
77
```

<figure><img src="/files/7v5P6Y4xbANlzdznduC3" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary><strong>Example 2: Wrap a value in an object</strong></summary>

Takes the incoming value (`$`) and wraps it inside a JSON object with a key named `temp_sensor_1`.

Data:

```json
25.4
```

Modifier content:

```
{ "temp_sensor_1": $ }
```

Return of the modifier:

```json
{ "temp_sensor_1": 25.4 }
```

<figure><img src="/files/V5wmkHsON7Ho15jJctF5" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary><strong>Example 3: Implicit function usage</strong></summary>

Trims whitespace and converts a raw string to uppercase without explicitly naming the input variable.

Data:

```json
"maintenance_required"
```

Modifier content:

```
$uppercase()
```

Return of the modifier:

```json
"MAINTENANCE_REQUIRED"
```

<figure><img src="/files/MX9Fzb3MMxwhRuOgINwE" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary><strong>Example 4: Filtering an array</strong></summary>

Returns only the objects from a list that meet a specific status condition.

Data:

```json
[
  { "id": "A1", "status": "OK" },
  { "id": "B2", "status": "ERROR" }
]
```

Modifier content:

```
$[status="ERROR"]
```

Return of the modifier:

```json
{ "id": "B2", "status": "ERROR" }
```

<figure><img src="/files/NUldpbnLCwVnegWSHsHo" alt=""><figcaption></figcaption></figure>

</details>

## JavaScript expressions

This modifier type accepts any standard JavaScript expression that evaluates to a new value. Reference the reserved variable `x` to access the preceding data output. For more information, see the MDN documentation on [JavaScript expressions and operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_operators).

### JavaScript expression examples

<details>

<summary><strong>Example 1: Conditional status (ternary)</strong></summary>

Determines a status string based on a numeric threshold.

Data:

```json
85.5
```

Modifier content:

```javascript
x > 80 ? "Critical" : "Normal"
```

Return of the modifier:

```
"Critical"
```

<figure><img src="/files/FAvVTa0b0aQKMD8W2G5M" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary><strong>Example 2: Array mapping and enrichment</strong></summary>

Iterates through an array of objects to add a new property or modify existing ones using `.map()`.

Data:

```json
[
  { "part": "Bolt", "qty": 10 },
  { "part": "Nut", "qty": 5 }
]
```

Modifier content:

```javascript
x.map(item => ({
  ...item,
  available: item.qty > 0,
  lastChecked: DateTime.now().toISODate()
}))
```

Return of the modifier:

```json
[
  { "part": "Bolt", "qty": 10, "available": true, "lastChecked": "2026-02-12" },
  { "part": "Nut", "qty": 5, "available": true, "lastChecked": "2026-02-12" }
]
```

<figure><img src="/files/clgFKaGXQhyWpeGsvrC7" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary><strong>Example 3: Multi-step logic (IIFE)</strong></summary>

Modifiers only support expressions. For more elaborate logic involving temporary variables, use the Immediately Invoked Function Expression (IIFE) pattern.

Data:

```json
{ "raw_value": 1024, "multiplier": 0.5 }
```

Modifier content:

```javascript
(() => {
  const base = x.raw_value;
  const factor = x.multiplier;
  const offset = 10;
  return (base * factor) + offset;
})()
```

Return of the modifier:

```json
522
```

<figure><img src="/files/rDq56jTuKYvYAlKPWYyA" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary><strong>Example 4: Removing and adding properties in an array</strong></summary>

Use the spread operator (`...`) to reproduce existing entries while selectively removing or adding properties.

Data:

```json
[ { "a": 1, "b": 1, "c": 1 }, { "a": 2, "b": 2, "c": 2 } ]
```

Modifier content:

```javascript
x.map(y => ({
  ...y,         // Reproduces existing entry
  c: undefined, // Removes property c
  d: 'cool'     // Adds property d
}))
```

Return of the modifier:

```json
[ { "a": 1, "b": 1, "d": "cool" }, { "a": 2, "b": 2, "d": "cool" } ]
```

<figure><img src="/files/joji1yCQmXD0iun4dwHV" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary><strong>Example 5: Processing multiple inputs (using <code>combine</code>)</strong></summary>

When using the `combine` function, the IIFE pattern cleanly handles multiple input sources stored in the `x` array.

Data (combined by the `combine` function):

```json
[
  [ { "name": "User1" } ], // x[0]
  [ { "asset": "CNC" } ]   // x[1]
]
```

Modifier content:

```javascript
(() => {
  const users = x[0]
  const assets = x[1]
  return {
    assigned_users: users,
    active_assets: assets
  }
})()
```

Return of the modifier:

```json
{
  "assigned_users": [ { "name": "User1" } ],
  "active_assets": [ { "asset": "CNC" } ]
}
```

<figure><img src="/files/8lNZz3PLTtu41EuossQK" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary><strong>Example 6: Date calculations (using Luxon)</strong></summary>

Heisenware provides built-in support for the [Luxon](https://moment.github.io/luxon/) library via the `DateTime`, `Duration`, and `Interval` objects for complex date and time operations.

{% hint style="warning" %}
`Duration` and `Interval` are only available from version v91.
{% endhint %}

Here are some common modifier patterns:

#### 1. Calculating future or past dates (addition and subtraction)

Data:

```json
[
  { "startDate": "2026-01-01", "days": 5 },
  { "startDate": "2026-01-10", "days": 2 }
]
```

Modifier content:

```javascript
x.map(y => ({
   ...y,
   dueDate: DateTime.fromISO(y.startDate).plus({ days: y.days }).toISODate()
}))
```

Return of the modifier:

```json
[
  { "startDate": "2026-01-01", "days": 5, "dueDate": "2026-01-06" },
  { "startDate": "2026-01-10", "days": 2, "dueDate": "2026-01-12" }
]
```

<figure><img src="/files/EjCUrvk4irabNG7i5f9q" alt=""><figcaption></figcaption></figure>

#### 2. Calculating downtime (time differences)

Find the exact duration between two timestamps, such as a machine fault start and end time.

Data:

```json
[
  { "machine": "Press A", "faultStart": "2026-03-12T08:00:00Z", "faultEnd": "2026-03-12T10:15:00Z" }
]
```

Modifier content:

```javascript
x.map(y => ({
   ...y,
   downtime: DateTime.fromISO(y.faultEnd)
      .diff(DateTime.fromISO(y.faultStart), ['hours', 'minutes'])
      .toFormat("h 'hrs' m 'mins'")
}))
```

Return of the modifier:

```json
[
  { "machine": "Press A", "faultStart": "2026-03-12T08:00:00Z", "faultEnd": "2026-03-12T10:15:00Z", "downtime": "2 hrs 15 mins" }
]
```

***

#### 3. Formatting decimal labor hours

Convert raw decimal hours from timesheets or logs into standard `HH:mm` timecode using the `Duration` object.

Data:

```json
[
  { "worker": "Alice", "loggedDecimal": 8.75 },
  { "worker": "Bob", "loggedDecimal": 7.1 }
]
```

Modifier content:

```javascript
x.map(y => ({
   ...y,
   standardTime: Duration.fromObject({ hours: y.loggedDecimal }).toFormat("hh:mm")
}))
```

Return of the modifier:

```json
[
  { "worker": "Alice", "loggedDecimal": 8.75, "standardTime": "08:45" },
  { "worker": "Bob", "loggedDecimal": 7.1, "standardTime": "07:06" }
]
```

***

#### 4. Validating events against shifts (intervals)

Check if a specific event (like a sensor trigger) occurred within a defined time window or shift using the `Interval` object.

Data:

```json
[
  { "eventTime": "2026-03-12T14:30:00Z", "shiftStart": "2026-03-12T06:00:00Z", "shiftEnd": "2026-03-12T18:00:00Z" },
  { "eventTime": "2026-03-12T20:00:00Z", "shiftStart": "2026-03-12T06:00:00Z", "shiftEnd": "2026-03-12T18:00:00Z" }
]
```

Modifier content:

```javascript
x.map(y => ({
   ...y,
   occurredDuringShift: Interval.fromDateTimes(
      DateTime.fromISO(y.shiftStart),
      DateTime.fromISO(y.shiftEnd)
   ).contains(DateTime.fromISO(y.eventTime))
}))
```

Return of the modifier:

```json
[
  { "eventTime": "2026-03-12T14:30:00Z", "shiftStart": "...", "shiftEnd": "...", "occurredDuringShift": true },
  { "eventTime": "2026-03-12T20:00:00Z", "shiftStart": "...", "shiftEnd": "...", "occurredDuringShift": false }
]
```

***

#### 5. Converting UTC sensor data to local time

IoT devices typically send data in UTC. Convert this to a readable local format for UI dashboards.

Data:

```json
[
  { "sensorId": "Temp-01", "utcTimestamp": "2026-03-12T07:43:50Z" }
]
```

Modifier content:

```javascript
x.map(y => ({
   ...y,
   localFormatted: DateTime.fromISO(y.utcTimestamp).toLocal().toFormat("dd. MMM yyyy, HH:mm:ss")
}))
```

Return of the modifier:

```json
[
  { "sensorId": "Temp-01", "utcTimestamp": "2026-03-12T07:43:50Z", "localFormatted": "12. Mar 2026, 08:43:50" }
]
```

</details>

<details>

<summary><strong>Example 7: Round robin (using <code>combine</code>)</strong></summary>

Sometimes you want to extract items of an array in a round-robin fashion. Use a `combine` function in which you link the modifier's output back to the second argument:

<figure><img src="/files/HnndV2BQQiNBjeOvkSnw" alt=""><figcaption></figcaption></figure>

Data:

```yaml
[a, b, c]
```

Modifier content:

```javascript
(() => {
  const [arr, prev] = x
  const last = prev ? prev : arr[0]
  const index = prev ? arr.indexOf(last) : -1
  const next = arr[(index + 1) % arr.length]
  return next
})()
```

Return of the modifier:

```
a // when triggered first time
b // second time
c // third time
a // fourth time
```

</details>

## Using AI for modifiers

Use AI chatbots (ChatGPT, Claude, Gemini) to generate or optimize your modifiers. This helps especially with complex transformations where you need to reshape large JSON objects on the fly.

For best results, copy this article as context for the AI. Use the Copy button at the top of the page or the Open in ChatGPT / Open in Claude buttons in the top navigation bar.

#### Recommended AI prompt

Alternatively, copy and paste this prompt into your AI so it understands the Heisenware environment and its variable references.

```
I am working in Heisenware, a node-based visual programming tool for industrial applications. 
I need a "modifier" expression that transforms data on the fly between functions.

Full documentation: https://docs.heisenware.com/app-builder/build-backend/extension-nodes/modifier.md

Rules:
* A modifier is a single expression that returns the transformed value. No statements or variable declarations.
* JSONata: the input data is referenced as $. Functions with empty parentheses () automatically process the incoming data, e.g. $uppercase().
* JavaScript: the input data is referenced as x. For multi-step logic with temporary variables, use an IIFE: (() => { ... })().
* JavaScript dates: use the Luxon library via the DateTime, Duration, and Interval objects.
* Unless I say otherwise, pick the simpler of JSONata or JavaScript for the task and tell me which type to select.
* Reply with the expression only, no explanation, no markdown fences.

My input data (sample):
[Paste a sample of the data arriving at the modifier here.]

My task:
[Describe your transformation, e.g., "Extract temp_c from each object in the array and calculate the average."]
```


# Filter

The filter acts as a conditional gate for your flow. It branches logic or halts it based on a condition and is the primary way to implement `if/else` scenarios in Heisenware.

To add a filter:

1. Click the + icon on the right side of a function output, modifier, or existing filter.
2. Select Filter from the list.
3. Click the new filter box (*Click to edit…*) to open the code editor and write your condition.

<figure><img src="/files/zm2x6quP3bMELcm6wlbK" alt=""><figcaption><p>randomInteger function with filter extension node</p></figcaption></figure>

## How filters work

A filter evaluates a JavaScript expression that must return a boolean value (`true` or `false`). The input value from the preceding output is available as the reserved variable `x`.

Click the filter icon on the left to evaluate the filter manually during development. The last result appears below the expression.

### Logical gate

If the result is `true`, the data passes on to the next node following the filter. If `false`, the flow halts at this point.

<div align="center"><figure><img src="/files/poJAOEoCLXDNFrKQPU1h" alt=""><figcaption></figcaption></figure></div>

### Branching logic

Use the `true` and `false` states of the filter to trigger separate logic paths. For example, use the `true` state to trigger another function.

<figure><img src="/files/1uA9E7OGfl7WLPG6Oal7" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}

#### Falsy values halt the flow

A filter condition that evaluates to a falsy value (e.g., `false`, `0`, `null`, `""`) stops the execution of the flow.
{% endhint %}

## Filter examples

### Example 1: Threshold monitoring

Checks if a sensor value exceeds a critical limit.

Data:

```json
{
  "temperature": 92.5,
  "unit": "°C"
}
```

Filter content:

```javascript
x.temperature > 90
```

Return of the filter: `true`

<figure><img src="/files/0IWLacfVtCY70lvbAYwX" alt=""><figcaption></figcaption></figure>

### Example 2: Industrial error detection

Inspects a status message for specific keywords like "Error".

Data:

```json
"System Error: PLC Communication Timeout"
```

Filter content:

```javascript
x.includes('Error')
```

Return of the filter: `true`

<figure><img src="/files/NSpQhwntSGu9xTeXxpa7" alt=""><figcaption></figcaption></figure>

### Example 3: Validating array data

Ensures that an array contains data before the flow processes it.

Data:

```json
[]
```

Filter content:

```javascript
x.length > 0
```

Return of the filter: `false`

<figure><img src="/files/Rm3Wz94Qn8s7Z1mxUbaz" alt=""><figcaption></figcaption></figure>

## Using AI for filters

Use AI chatbots like ChatGPT, Claude, or Gemini to generate complex filter logic. Filters use standard JavaScript, so provide the AI with your data structure to get an immediate result.

For best results, copy this article as context for the AI. Use the Copy button at the top of the page or the Open in ChatGPT / Open in Claude buttons in the top navigation bar.

#### Recommended AI prompt

Copy and paste this prompt into your AI so it understands the Heisenware environment and its variable references.

```
I am working in Heisenware, a node-based visual programming tool for industrial applications. 
I need a "Filter" expression that acts as a conditional gate in a flow.

Full documentation: https://docs.heisenware.com/app-builder/build-backend/extension-nodes/filter.md

Rules:
* A filter is a single JavaScript expression that must return true or false. JSONata is not supported here.
* The input data is referenced as x.
* If the result is falsy, the flow halts at the filter.
* No statements or variable declarations. For multi-step logic, use an IIFE: (() => { ... })().
* Reply with the expression only, no explanation, no markdown fences.

My input data (sample):
[Paste a sample of the data arriving at the filter here.]

My task:
[Describe your condition, e.g., "Only continue if pressure is between 2.0 and 4.5 bar."]
```


# Recorder

The recorder captures a [function](/app-builder/build-backend/functions)'s output and stores it as timeseries data in the [internal InfluxDB](/app-builder/build-backend/functions/storage/timeseries-database#quick-start-the-internal-instance). Use it to record a data stream, visualize it in your Apps, or analyze it later. It records during build time (in test mode) and during the App's runtime.

## Settings

* **Measurement name**: Fill the data point name box with a unique name. You need this name to find and read the recorded data.
* **Recording type**: Right-click the recorder to select how long the data is stored: 1 hour (H, default), 1 day (D), 1 week (W), 1 month (M), 1 year (Y), or downsampled (DS) for long-term storage in [downsampled form](/app-builder/build-backend/functions/storage/timeseries-database#downsampling-pipeline).

<figure><img src="/files/KszVQeTxO1dHUeehUvma" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
If the [Industrial Blockchain](/app-builder/build-backend/functions/extensions/industrial-blockchain) extension is available in your account, an additional Blockchain (BC) recording type appears. It stores the data in the blockchain instead of InfluxDB.
{% endhint %}

## Reading recorded data

Click the letter icon inside the recorder to generate a matching readout function directly on the canvas. Depending on the recording type, this is the `read` or `readDownsampled` function of the internal InfluxDB (or the blockchain `read` function), preconfigured with your measurement name.


# Error handler

The error handler manages errors thrown by a function. It opens a separate output that only activates when the function fails or throws an exception. Unlike the other extension nodes, the error handler attaches directly to a function only, not to other extension nodes.

Build a dedicated logic path from this output to handle error conditions, for example to log the error details to a database or display an error message in the UI. Wire the error handler to widgets or function triggers like any other output, and chain further extension nodes behind it, for example a modifier to reshape the error message.

The captured error message appears below the error handler. Right-click it to clear the content or delete the node.

<figure><img src="/files/Xpb02DuadNfOptJR5iPi" alt=""><figcaption><p>Error simulator function with captured error message and JSONata modification</p></figcaption></figure>


# Agents

An Agent is a small piece of Heisenware software that you install on a machine inside a separated network, for example on a factory floor. It executes logic, like connectors for S7, Modbus, or OPC UA, directly where the systems and devices are, and exchanges data securely with your account. Agents distribute your App logic: parts of it run in the cloud, parts of it at the edge, next to the machines it talks to.

<div data-full-width="true"><figure><img src="/files/Yvvw8Iolpmc8WlslO1oC" alt="" width="525"><figcaption><p>Heisenware Agent</p></figcaption></figure></div>

## How Agents work

1. Build or download an Agent and install it on a machine inside the target network.
2. The Agent connects to the Heisenware platform through an outbound-only MQTTS connection on port 8883. No inbound firewall rules or VPNs are required.
3. Once online, the Agent appears in the [Function Explorer](/app-builder/build-backend/functions/function-explorer) as its own entry, holding the connectors it carries.
4. Functions dragged from an Agent entry execute on the Agent's machine, directly at the edge.

Agents run as system services or containers. They start automatically after reboots and power cycles and stay available around the clock.

{% hint style="info" %}

#### A function is a function

In the App Builder, you never notice that you are working on a machine in a different network. A function from an Agent looks and behaves like any other function: drag it onto the canvas, wire it, configure it. It just runs somewhere else. Only its [address](/app-builder/build-backend/functions#advanced-addressing) reveals where.
{% endhint %}

## Types of Agents

Choose the Agent that matches your edge hardware:

<table><thead><tr><th width="220">Type</th><th>Choose when</th></tr></thead><tbody><tr><td><a href="/pages/VvOcrsg9EHHHqMzfqvEt"><strong>Native Agent</strong></a></td><td>You have a Windows, macOS, or Linux machine (including ARM64 industrial PCs). Installs as a background service directly on the operating system. Credentials are built into the installer.</td></tr><tr><td><a href="/pages/caMewSD7QZI0Or3GhvxI"><strong>Docker Agent</strong></a></td><td>Your edge infrastructure already runs Docker. Same functionality in an isolated container. Pass credentials as environment variables at startup.</td></tr><tr><td><a href="/pages/mPmb7x25E9VeoNMaDFkl"><strong>LXC Agent (Insys)</strong></a></td><td>Your edge device is an INSYS icom industrial router or gateway (MRX, MRO, ECR, SCR series). Distributed as a <code>.tar</code> update packet and installed via the router's web interface.</td></tr></tbody></table>

Every [Native Agent](/app-builder/build-backend/agents/native-agent) you build is also stored in the [File Explorer](/app-builder/build-backend/file-explorer) in the `native-agents` folder, ready to download again at any time.


# Native Agent

The Native Agent is a fully installable package. It registers itself as a background service (a Windows service or Linux daemon), so it runs around the clock without a logged-in user.

## How it works

* **Persistence**: The operating system manages the Agent (systemd on Linux, Service Manager on Windows). If the machine reboots, the Agent starts automatically.
* **Security**: The Agent connects through an outbound-only MQTTS connection on port 8883. No inbound firewall rules or VPNs are required.
* **Compatibility**: Available for Windows, macOS, Linux (standard and Alpine), and ARM64 (for industrial PCs).

## Installing the Native Agent

{% stepper %}
{% step %}

#### Configure and build

In the [Function Explorer](/app-builder/build-backend/functions/function-explorer), click the create Agent icon (<i class="fa-cloud-arrow-down">:cloud-arrow-down:</i>).

* **Connectors**: Select the connectors (e.g., S7, SQL) this Agent should carry.
* **Target OS**: Choose the operating system of the machine where the Agent will run.
* **Prefix (optional)**: Enter a [prefix](#using-a-prefix-for-fleet-deployment) if you plan to deploy the same file to multiple machines (e.g., `milling-machine`). Each instance then generates its own unique ID (e.g., `milling-machine-abc123`).
* Click *Prepare for download* to compile and download your installer package.

<figure><img src="/files/IG0ea5wL8f5nsXqNHrVS" alt="" width="375"><figcaption></figcaption></figure>

{% hint style="info" %}

#### Lost your file?

All Agents you have built are backed up on the [file server](/app-builder/build-backend/file-explorer) in the `native-agents` folder.
{% endhint %}
{% endstep %}

{% step %}

#### Run the installer

Move the package to the target machine, unzip, and run the installer.

* **Windows**: Run the `.exe` installer. It registers the service and starts the Agent automatically.
* **Linux/macOS**: Run the provided install script. You likely need `sudo` privileges so the Agent can register as a system daemon.
  {% endstep %}

{% step %}

#### Automatic discovery

The service starts immediately after installation. The Agent and its connectors appear in the [Function Explorer](/app-builder/build-backend/functions/function-explorer). Drag these functions onto the Backend Builder canvas. In production Apps, they execute locally on the machine running the Agent.
{% endstep %}
{% endstepper %}

{% hint style="warning" %}

#### Troubleshooting: check port 8883

The Agent requires port 8883 to be open for outbound traffic. If the Agent runs but does not appear in your Function Explorer, ask your IT administrator to check whether a firewall blocks this port.
{% endhint %}

## Managing the Agent service

The Agent runs as a service and has no user interface window. Manage its state with the standard OS tools:

* **Windows**: Open the Services app (`services.msc`), find the Heisenware Agent, and use the Start, Stop, or Restart controls.
* **Linux**: Manage the daemon on the command line:
  * `sudo systemctl status heisenware-agent`
  * `sudo systemctl restart heisenware-agent`

## Using a prefix for fleet deployment

The prefix option changes how an Agent identifies itself. Use it to manage a fleet of similar machines or devices.

* **Without a prefix (default)**: The Agent has a built-in, unique ID. You can move the installer to different computers, but they are all recognized as the same single Agent.
* **With a prefix**: The Agent generates a new, unique ID on its first launch in a specific directory. Deploy the exact same installer on multiple machines and each one connects as a separate entry in your Function Explorer (e.g., `milling-machine-abc123`, `milling-machine-xyz789`).

{% hint style="danger" %}
**Irreversible action**

Do not move an Agent folder that was created with a prefix after it has run for the first time. It relies on a hidden ID file in its directory to maintain its unique identity.
{% endhint %}


# Docker Agent

The Docker Agent provides the same functionality as the [Native Agent](/app-builder/build-backend/agents/native-agent) but runs in an isolated Docker container. It is the right choice for edge gateways or servers where you already manage your infrastructure with Docker.

## Key differences

* **Containerized execution**: Runs in an isolated Docker container instead of directly on the host operating system.
* **Environment configuration**: Unlike the Native Agent, the Docker Agent does not include built-in credentials. Provide them as environment variables at startup.
* **Hardware and network access**: To reach local networks, USB devices, or persist data, use standard Docker features like host networking or volume mounting.
* **Platform independent**: Runs on any platform that supports Docker.

## Where to get it

The Docker Agent is available as a publicly downloadable image:

```
heisenware/docker-agent:<version>
```

Find all available versions on [Docker Hub](https://hub.docker.com/r/heisenware/docker-agent).

## How to use it

Configure the following environment variables when running the container:

```bash
docker run -it \
-e HW_DOMAIN=<account>.<workspace> \
-e HW_BROKER=mqtts://<account>.heisenware.cloud \
-e HW_USERNAME=<username> \
-e HW_PASSWORD=<password> \
-e HW_AGENT_ID=<unique-id> \
heisenware/docker-agent:v91-slim
```

### Retrieving credentials

To get `HW_USERNAME` and `HW_PASSWORD`, first add a [VRPC integration](/app-manager/inbound-integrations#vrpc-client) in the App Manager.

### Example

For an account named `my-company`, an integration with the username `agentRunner`, and the password `secret`:

```bash
docker run -it \
-e HW_DOMAIN=my-company.default \
-e HW_BROKER=mqtts://my-company.heisenware.cloud \
-e HW_USERNAME=agentRunner \
-e HW_PASSWORD=secret \
-e HW_AGENT_ID=my-agent-1 \
heisenware/docker-agent:v91-slim
```

Once the connection is established, the console shows a confirmation screen indicating the Agent is online and connected to the workspace.

<figure><img src="/files/IgYQAmBoNJrrDu3pTUVo" alt=""><figcaption></figcaption></figure>

## Persisting data

To keep your data and configurations (such as created instances) across container restarts or updates, mount the `/shared` volume to a persistent location on your host machine:

```bash
-v /path/on/host:/shared
```


# LXC Agent (Insys)

The LXC Agent is a specialized version of the Heisenware Agent for edge computing on INSYS icom industrial routers and gateways (such as the MRX, MRO, ECR, and SCR series). It runs as an isolated Linux system container (LXC) directly within the router's icom SmartBox environment.

## Key differences

* **Native edge integration**: Runs directly on the router's firmware. No separate industrial PC or Raspberry Pi needed.
* **Pre-packaged format**: Distributed as a self-contained `.tar` update packet that the INSYS router natively understands.
* **Resource optimized**: The container caps its memory usage (128 MB heap) automatically so the router's core networking functions are never interrupted.
* **Automatic persistence**: Maps standard container volumes to the router's internal flash memory, so configurations survive firmware updates.

## Where to get it

The LXC Agent is available as a downloadable `.tar` archive from the public release server. Select the correct architecture for your INSYS gateway:

* **ARMv7** (standard for most MRX/MRO/SCR gateways): `heisenware-insys-<version>-armv7.tar`
* **ARM64**: `heisenware-insys-<version>-arm64.tar`

For example, download the required file directly with `wget`:

```bash
wget "https://downloads.heisenware.cloud/public/heisenware-insys-v92-beta0-armv7.tar"
```

{% hint style="info" %}
Check your INSYS router's datasheet if you are unsure which architecture it uses.
{% endhint %}

## How to use it

The LXC Agent runs on a hardware appliance, so you configure it through the INSYS icom web interface instead of command-line tools.

{% stepper %}
{% step %}

#### Upload the update packet

Log into your INSYS router's web interface and navigate to the Container menu. Upload the `.tar` file you downloaded. Assign the container an instance name (e.g., `heisenware-agent`).
{% endstep %}

{% step %}

#### Configure networking

In the container's network settings, map it to an internal network bridge (e.g., `net2` or `lan`). Assign it a dedicated IPv4 address, subnet mask, and gateway.

{% hint style="warning" %}

#### Port 8883 required

Like every Agent, the LXC container needs outbound internet access on port 8883 to connect to the Heisenware platform. Make sure the router's firewall allows this traffic for the container's IP address.
{% endhint %}
{% endstep %}

{% step %}

#### Activate the profile (initial boot)

Click Activate Profile in the INSYS UI. The router boots the LXC container for the first time, extracting the application payload and generating the persistent data directories.
{% endstep %}

{% step %}

#### Provide environment variables (`config.env`)

INSYS LXC containers behave like full lightweight virtual machines, so environment variables cannot be passed through the router's web interface. Provide them via a configuration file instead:

1. Access the container's file system via SSH or SFTP (using the container's newly assigned IP address).
2. Create a text file named `config.env` inside the persistent `/data/` folder.
3. Add the following keys to connect the Agent to your workspace:

```
HW_DOMAIN=<account>.<workspace>
HW_BROKER=mqtts://<account>.heisenware.cloud
HW_USERNAME=<your-vrpc-username>
HW_PASSWORD=<your-vrpc-password>
HW_AGENT_ID=<a-unique-id-for-this-gateway>
```

Generate the username and password by creating a [VRPC integration](/app-manager/inbound-integrations) in the App Manager.
{% endstep %}

{% step %}

#### Restart the container

Restart the container via the INSYS web interface. On reboot, the Agent automatically detects and parses the `/data/config.env` file. Once the connection is established, the Agent appears in your [Function Explorer](/app-builder/build-backend/functions/function-explorer).
{% endstep %}
{% endstepper %}

## Persisting data

The LXC Agent handles persistence automatically. The LXC Agent symlinks its internal `/shared` directory to the INSYS router's persistent `/data` partition.

* The router safely stores configurations and instances in its flash memory.
* If you update the Agent by uploading a newer `.tar` file to the same instance, your data stays intact and re-attaches to the new version.
* Backing up the router's profile via the INSYS web interface includes the Agent's configuration state.


# File Explorer

The File Explorer is the panel on the left that gives access to your account's internal file server. It is the central place for the files your App works with: data files your logic reads and writes, images for the UI, or PDFs for template backgrounds.

By default, the File Explorer shows the `uploads` folder, where your uploaded files live. You can also navigate to other areas of the file server, such as the `native-agents` folder holding your built [Agents](/app-builder/build-backend/agents).

{% hint style="warning" %}
Leave the advanced areas outside `uploads` untouched unless you know what you are doing.
{% endhint %}

## Uploading files

1. Click the upload icon (<i class="fa-cloud-arrow-up">:cloud-arrow-up:</i>) at the top of the File Explorer.
2. Drag and drop a file or click to select one from your computer.
3. Click Upload. The file is now ready to be used by your functions.

## Managing files

Right-click any file to open the context menu. Here you can:

* Download the file.
* Create a new folder to organize your assets.
* Rename a file or folder.
* Delete a file or folder.
* Copy the file's path to use it directly in function configurations.

<figure><img src="/files/NwPuHIXS6rcoWvWjL7Pj" alt=""><figcaption></figcaption></figure>

{% hint style="danger" %}
**Irreversible action**

Be careful when renaming or deleting a file. If a function (like `readCsv`) or a PDF template already uses that file path, your logic breaks.
{% endhint %}

## Common use cases

* **Data ingestion**: Upload `.csv` or `.json` files for your logic to process.
* **UI assets**: Store images and illustrations to drag into the UI of your App.
* **Document generation**: Store the PDF master files that serve as backgrounds in the [PDF Template Editor](/app-builder/build-frontend/pdf-template-editor).
* **Agent backups**: Every [Native Agent](/app-builder/build-backend/agents/native-agent) you build lands in the `native-agents` folder, ready to download again.


# Build frontend

The UI is what users of your Apps see and interact with. It ranges from simple dashboards and data visualizations to interactive Apps for user input, file management, and more.

{% hint style="info" %}

#### Optional user interface

The UI is optional. You can build headless Apps that use pure backend logic, like a data bridge between a PLC and a SQL database, running silently with no visual frontend.
{% endhint %}

## Core UI components

* [**Widgets**](/app-builder/build-frontend/widgets): The functional components of your App. They display live data, capture user input, or trigger logic.
* [**Pages**](/app-builder/build-frontend/page-explorer): The individual screens of your App. Create multiple pages and subpages to structure your App logically, then configure navigation elements so users can move between them.
* [**Text, icons, and images**](/app-builder/build-frontend/text-icons-and-images): Mostly static elements used for branding, instructions, and non-interactive content.
* [**PDF templates**](/app-builder/build-frontend/pdf-template-editor): Visual layouts for generating dynamic documents. Map variables onto a document background, then populate them from your backend logic.
* [**Theme**](/app-builder/build-frontend/theme-editor): The global visual DNA of your App. Ensures a consistent look across all widgets and pages.

## Frontend Builder

Turn backend logic into a functional, user-facing App inside the Frontend Builder. Place static elements for context and dynamic widgets on each page, then configure them using backend logic.

Build Apps for any screen size and switch the preview as you go to verify that your layout holds up on everything from a smartphone to a large desktop monitor.

### The toolbar

The toolbar serves as your main kit for composing the interface. It holds buttons and icons to:

* Add a text box, icon, or widget.
* Switch the screen preview.
* Extend page height to enable scrolling and scale the view.
* Edit or delete the selected widget. These icons (pen and trash) activate only when you select a widget or UI element.

<figure><img src="/files/LbNIsJiBJmNp1n1cSvTv" alt=""><figcaption></figcaption></figure>

### Placing and moving elements

Add an element by selecting it from the toolbar and clicking anywhere on the canvas. Once placed, you can:

* **Move**: Drag the element to a new position on the canvas.
* **Resize or rotate**: Use the grab markers on the corners and edges to change the element's dimensions or orientation.
* **Open settings**: Double-click the widget, or select it and click the pen icon in the toolbar.
* **Align with snaplines**: Snaplines appear automatically to help align widgets and other UI elements with each other.
* **Pixel-perfect positioning**: Hold the Shift key while moving an element to temporarily disable snaplines for precise placement.
* **Adjust layers and layout**: Right-click any element to adjust the stacking order of overlapping items, stretch it to full width, or toggle tile view.

<figure><img src="/files/l6DjPlfma7EqObD2bFKO" alt="" width="563"><figcaption><p>Frontend Builder basics</p></figcaption></figure>

{% hint style="warning" %}

#### Screen-specific layout saving

Heisenware saves changes to an element's position or size per device size. Always check other screen previews to ensure the layout stays clean across all hardware.
{% endhint %}

### Context menu tools

Right-click any element to open a menu for quick layout actions and layer management.

* *Order*: Adjust the stacking of overlapping elements to control which item appears in the foreground or background.
* *Full width*: Instantly stretches the element to fill the entire horizontal space of your current screen preview.
* *Toggle tile view*: Switches the element into a tiled display mode.

### Screen preview and responsive behavior

[Heisenware Apps](/production-apps/overview) are responsive by nature and adapt to different screen sizes automatically. Control exactly how your App behaves on different hardware using these toolbar tools:

* **Switching previews**: Click the screens icon (<i class="fa-laptop-mobile">:laptop-mobile:</i>) and click a device icon to switch to the corresponding UI editor and adapt your layout.

<figure><img src="/files/CGivFfgL278F2br5xB1y" alt=""><figcaption></figcaption></figure>

* **Enable or disable screens**: Right-click any device icon to enable or disable specific screen sizes. By default, only the phone, tablet, and laptop are active. When a user opens your App on a disabled screen size, Heisenware scales the layout from the nearest active device size.
* **Content alignment (L and XL)**: On large monitors, decide how the overall content sits on the screen. Right-click the L or XL icons to choose between left-aligned or centered layouts.

<figure><img src="/files/mTZZrtW3zebxh6u2hmoL" alt=""><figcaption></figcaption></figure>

* **Scaling**: Use the scaling bar to zoom the current preview in or out. This serves as a design-time aid only and does not change the App's actual size for the user.
* **Extend height**: Use the page height icon (<i class="fa-arrows-up-down">:arrows-up-down:</i>) in the toolbar to add vertical space and enable scrolling for the selected device size. This lets you scroll on mobile while keeping a fixed dashboard on desktop. If a page height does not change when you reduce it, a widget is likely positioned outside the valid area. Move or delete that widget first.

{% hint style="info" %}

#### Mobile-first workflow best practices

By default, Heisenware inherits changes upward: changes configured on a smaller screen propagate to larger ones.

1. **Start with phone**: Design your layout for the phone first to ensure your basic structure is solid.
2. **Scale up**: Switch to tablet or laptop views and arrange the widgets to utilize the extra horizontal space.
3. **Fine-tune**: Adjustments on a larger screen stay local to that view, letting you optimize control-room monitors down to the pixel without breaking the mobile experience.
   {% endhint %}


# Widgets

Widgets are the interactive building blocks of your App's UI. Static elements set the context; widgets work with your backend logic to display live data, capture user input, and trigger functions and flows. See [display widgets](/app-builder/build-frontend/widgets/display-widgets), [input widgets](/app-builder/build-frontend/widgets/input-widgets), and [trigger widgets](/app-builder/build-frontend/widgets/trigger-widgets) for details.

## Configuration

Double-click a widget, or select it and click the edit icon on the toolbar, to open its settings. Most settings are unique to the specific widget.

These settings let you:

* **Customize visuals**: Adjust colors, labels, and styling to match your brand.
* **Define behavior**: Set default values, limits, or interaction rules.
* **Toggle features**: Enable or disable additional widget functionality, such as search bars.

### Context menu tools

Right-click any widget to open a menu for quick actions and data settings. Besides the general options (order, full width, tile view), you can:

* **Toggle multi-tenancy**: Controls how users see data.
  * **Isolated**: Each user sees only their own data, based on their session filters. Another user can filter differently without affecting your view. This is the default setting.
  * **Shared**: Every user sees the same data in real time. If one user applies a filter, it updates globally for everyone viewing the App.
* **Unlink all**: Clears every connection between the widget and your backend flows in a single click.

## Data binding

A widget operates once you link it to the [Backend Builder](/app-builder/build-backend) through its properties, which serve as connection points that carry data in and out.

### How to link

1. Select the widget in the [Frontend Builder](/app-builder/build-frontend) (optional).
2. Drag a [function](/app-builder/build-backend/functions) part (an input, trigger, or output) or a [modifier](/app-builder/build-backend/extension-nodes/modifier) from the [Backend Builder](/app-builder/build-backend) and drop it onto the widget.
3. Pick a widget property inside the menu. The platform selects the main property automatically.

To break a link, click the `x` next to the property in the linked function, or use the widget's context menu to unlink all.

### Data direction mechanics

Drag from the function or extension node onto the widget. The selected slot determines the behavior:

* **Function output or modifier to widget**: A function output or modifier writes into a widget property, such as feeding a dataset into a chart or a status into a status lamp. Data flows from logic to the UI.
* **Widget to function input**: A widget event flows into a function input. Each event carries its data payload. For example, when a user edits a value in a data grid, the modified record travels into the function immediately. For some widgets, editing events only fire when you enable the corresponding setting on the widget.
* **Button to function trigger**: Connect a function trigger to a [button](/app-builder/build-frontend/widgets/trigger-widgets/button) so a click executes the function. The trigger transmits no data. This applies strictly to buttons since they are the only trigger widget, though you can also configure [icons](/app-builder/build-frontend/text-icons-and-images) to act as buttons.

{% hint style="info" %}

#### Auto-triggering on input

To execute a function automatically from UI input instead of a click, wire the input of the function to its trigger. The incoming data feeds and executes the function without requiring a button.
{% endhint %}


# Input widgets

Input widgets capture data from your users and their devices, handling everything from a single signature to a multi-field form. Collected data flows directly into your backend logic for processing, storage, or analysis.

{% hint style="info" %}

#### Widget versatility and categorization

The platform groups widgets by their primary purpose, though many serve multiple roles. For example, a [form](/app-builder/build-frontend/widgets/input-widgets/form) (an [input widgets](/app-builder/build-frontend/widgets/input-widgets)) can display data, and a [data grid](/app-builder/build-frontend/widgets/display-widgets/data-grid) (a [display widgets](/app-builder/build-frontend/widgets/display-widgets)) can capture input. Check the properties of each widget to see its full capabilities.
{% endhint %}

## Available input widgets

The toolbar contains the following input widgets, each featuring distinct configuration and data properties:

* [**Barcode / QR**](/app-builder/build-frontend/widgets/input-widgets/barcode-qr): Scans and decodes barcode and QR code formats using the device camera.
* [**Upload**](/app-builder/build-frontend/widgets/input-widgets/upload): Lets users upload files directly from their device.
* [**Form**](/app-builder/build-frontend/widgets/input-widgets/form): Builds complex data-entry layouts with varied field types, field grouping, and validation rules.
* [**Photo**](/app-builder/build-frontend/widgets/input-widgets/photo): Captures images using the device camera.
* [**Signature**](/app-builder/build-frontend/widgets/input-widgets/signature): Captures handwritten signatures as image strings.

## Data binding

Input widgets exchange data with backend logic using the [Backend Builder](/app-builder/build-backend).

### How to link

Link a widget by dragging logic onto it:

1. Drag a [function](/app-builder/build-backend/functions) component (input or output) or a [modifier](/app-builder/build-backend/extension-nodes/modifier) onto the widget.
2. Select the target widget property inside the configuration menu.

### Interaction types

* **Widget to function input**: The widget transmits user entries into a function input property.
* **Function output or modifier to widget**: A function output or modifier transmits data to update the widget. For example, linking a function output to the `clear` property of a [form](/app-builder/build-frontend/widgets/input-widgets/form) resets the form automatically when the flow executes that function.

## Configuration

Widget properties control behavior, appearance, and backend data exchange. Configure properties using two methods:

* **Static configuration**: Define the property inside the settings panel. The value remains fixed.
* **Data binding**: Drive the property from backend logic at runtime to update the widget live as data flows through the App.

{% hint style="info" %}

#### Property configuration methods

Not every property supports both methods. Some properties exist exclusively inside the settings panel, others require data binding, and many support both. Individual widget pages list bindable properties in data binding tables and settings panel fields under configuration.
{% endhint %}

## Automatic data isolation

The platform isolates data for every input widget per user and session automatically.

* **Default isolation**: Data never mixes if different users interact with the same form.
* **Session persistence**: Data remains tied to the specific user session as it moves through a flow.
* **User references**: Reference the active user ID in backend logic using the `$USER` variable. This variable returns the user email address in authenticated Apps or a unique session string in public Apps.


# Barcode / QR

The barcode / QR widget uses a device's built-in camera to scan and decode various barcode formats, such as QR codes and traditional product bar codes. It opens an interactive full-screen camera view directly in your Apps to capture logistical or inventory data fast.

<figure><img src="/files/PIONf4JGck9J0L2BUlKz" alt=""><figcaption><p>The barcode / QR scanner button in the UI</p></figcaption></figure>

## Data binding

### Widget to function input

| **Property** | **Description**                                                                                                  | **Type**        |
| ------------ | ---------------------------------------------------------------------------------------------------------------- | --------------- |
| `text`       | Fires whenever the camera successfully decodes a barcode. The payload type depends on your configured scan mode. | string \| array |

### Function output or modifier to widget

| **Property** | **Description**                                                                                                              | **Type** |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------- | -------- |
| `clear`      | Clears any scanned values currently held in memory when a true signal is received.                                           | boolean  |
| `scanMode`   | Overrides the operational scan mode property dynamically at runtime (options include `single` or `multiple`).                | string   |
| `button`     | Passes a structured configuration object to change button text labels, visual styles, or disabled states from backend logic. | object   |

### Data formats

The structure of the data output emitted by the `text` property shifts automatically based on your active scanning configuration.

**Single scan mode output**

When scan mode is configured as `single`, the widget captures a single code, outputs it as a plain text string block, and immediately terminates the camera session: `"7501030491234"`

**Multiple scan mode output**

When scan mode is configured as `multiple`, the user can scan numerous items continuously without closing the viewfinder. Clicking the confirm checkmark button outputs all collected items as a clean array of unique strings:

```json
[
  "7501030491234",
  "9780593135822",
  "049000028904"
]
```

## Configuration

Set the widget's defaults in the settings panel. Since the activation button is the only permanently visible element on the page layout, most settings define its design.

### General settings

| **Property** | **Label** | **Description**                                                                                                   | **Type**         |
| ------------ | --------- | ----------------------------------------------------------------------------------------------------------------- | ---------------- |
| `scanMode`   | Scan mode | Sets whether the camera interface captures a `single` item and closes, or collects `multiple` items continuously. | string           |
| `width`      | Width     | Sets the external layout width dimension of the scan button container.                                            | string \| number |
| `height`     | Height    | Sets the external layout height dimension of the scan button container.                                           | string \| number |

### Button styling settings

| **Property**  | **Label**          | **Description**                                                                                                                   | **Type** |
| ------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `text`        | Button text        | The main text label displayed inside the scan button body.                                                                        | string   |
| `icon`        | Icon               | The font icon class rendered next to the text label inside the button framework.                                                  | string   |
| `fontSize`    | Text size          | The typographical font size of the button's text label.                                                                           | integer  |
| `iconSize`    | Icon size          | The visual display text size of the button's icon class.                                                                          | integer  |
| `type`        | Button type        | Sets the contextual theme color layout of the button frame (options include `default`, `normal`, `success`, `danger`, or `back`). | string   |
| `stylingMode` | Styling mode       | Sets the visual frame style variant of the button (options include `contained`, `outlined`, or `text`).                           | string   |
| `hint`        | Hover text         | Tooltip text content revealed when a cursor hovers directly over the button area.                                                 | string   |
| `disabled`    | Initially disabled | Checks whether the button is disabled and unclickable when the page layout first instantiates.                                    | boolean  |

### Button object schema

When bypassing default panel properties by binding a custom runtime payload to the `button` property slot, use the following structural key configuration:

| **Property**  | **Description**                                                                    | **Type** |
| ------------- | ---------------------------------------------------------------------------------- | -------- |
| `text`        | Overrides the display text label printed on the button frame.                      | string   |
| `fontSize`    | Overrides the typographical font size of the label text.                           | integer  |
| `iconSize`    | Overrides the visual icon scale size inside the button frame.                      | integer  |
| `type`        | Overrides the button theme color layout selection.                                 | string   |
| `stylingMode` | Overrides the frame visual border fill variant.                                    | string   |
| `disabled`    | Toggles whether user click interaction with the scan button is locked or unlocked. | boolean  |

## Tips and tricks

{% hint style="info" %}

#### Viewfinder rendering overlays and hardware haptics

When active, the camera interface generates a black modal overlay layout directly attached via portals to the application viewport base layer, rendering on top of all other elements. If you have multiple camera lenses available on your hardware, use the interactive camera rotation icon inside this overlay framework to toggle between available feeds.

Every successful code collection triggers a short haptic device vibration pulse (`200ms`) automatically to confirm registration without requiring screen inspection.
{% endhint %}


# Upload

The upload widget handles file and photo uploads. Users select one or more files from their local storage or capture images directly using their device camera. The widget stores each item as a physical file on the server or as a Base64-encoded string, and displays an interactive preview list of all uploaded items.

<figure><img src="/files/cHs1XdWmd4ZuTNTPxWko" alt=""><figcaption><p>A full and an empty upload widget</p></figcaption></figure>

## Data binding

### Widget to function input

| **Property** | **Description**                                                                            | **Type** |
| ------------ | ------------------------------------------------------------------------------------------ | -------- |
| `files`      | Fires when a user uploads or deletes a file. The payload carries an array of file objects. | array    |

### Function output or modifier to widget

| **Property** | **Description**                                                  | **Type** |
| ------------ | ---------------------------------------------------------------- | -------- |
| `files`      | Populates the widget with an existing array of file objects.     | array    |
| `clear`      | Clears all uploaded files from the widget interface when `true`. | boolean  |
| `isLoading`  | Displays a loading indicator when `true`.                        | boolean  |
| `button`     | Overrides the upload button configuration at runtime.            | object   |

### Data formats

The structure of the file objects inside the `files` array depends on your configured storage type.

**File storage payload**

When `storageType` is set to `file`, the payload provides a server path:

```json
{
  "lastModified": 1678886400000,
  "name": "document.pdf",
  "size": 102400,
  "type": "application/pdf",
  "path": "/shared/runtime-files/a1b2c3d4e5.pdf"
}
```

**Buffer storage payload**

When `storageType` is set to `buffer`, the payload provides a Base64-encoded string:

```json
{
  "lastModified": 1678886400000,
  "name": "image.png",
  "size": 51200,
  "type": "image/png",
  "base64": "iVBORw0KGgoAAAANSUhEUgA..."
}
```

## Configuration

Set the widget's defaults in the settings panel.

### General settings

| **Property**      | **Label**               | **Description**                                                                                                                                            | **Type** |
| ----------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `storageType`     | Storage type            | Controls whether the widget stores each file as a physical file on the server (`file`) or as a Base64 string (`buffer`).                                   | string   |
| `multiple`        | Allow multi-file upload | Allows users to select and upload several files simultaneously when `true`. Live camera captures via the photo category still execute one image at a time. | boolean  |
| `showThumbnails`  | Show thumbnails         | Displays a preview thumbnail layout for uploaded image files when `true`.                                                                                  | boolean  |
| `thumbnailHeight` | Thumbnail size          | Sets the layout height of the preview thumbnails in pixels.                                                                                                | number   |

### Restriction settings

Configure these validation and processing behaviors inside the restrictions property group.

| **Property**  | **Label**               | **Description**                                                                                                                                                             | **Type**         |
| ------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
| `accept`      | Restrict file types     | Specifies the allowed file categories for upload. Supported categories include text, documents, spreadsheets, presentations, images, audio, video, archives, web, or photo. | array            |
| `maxFiles`    | Maximum number of files | Sets the total number of files the widget can hold. The interface automatically disables the upload controls when reaching this limit.                                      | integer          |
| `aspectRatio` | Aspect ratio            | Enforces a specific crop aspect ratio on image captures taken via the live camera when the photo category is active.                                                        | number or string |
| `resolution`  | Resolution              | Adjusts the target resolution quality optimization for image captures taken via the live camera, supporting `preview`, `balanced`, `high`, or `original`.                   | string           |

#### Allowed file categories and extensions

The `accept` configuration limits user selections to the following mapped extensions:

* **Text**: `.txt`, `.md`
* **Documents**: `.doc`, `.docx`, `.pdf`, `.rtf`, `.odt`
* **Spreadsheets**: `.xls`, `.xlsx`, `.ods`, `.csv`
* **Presentations**: `.ppt`, `.pptx`, `.odp`
* **Images**: `.jpg`, `.jpeg`, `.png`, `.gif`, `.bmp`, `.tiff`, `.svg`, `.webp`, `.heic`, `.heif`
* **Audio**: `.mp3`, `.wav`, `.flac`, `.aac`, `.ogg`, `.wma`
* **Video**: `.mp4`, `.avi`, `.mov`, `.wmv`, `.mkv`, `.flv`
* **Archives**: `.zip`, `.rar`, `.7z`, `.tar`, `.gz`, `.iso`
* **Web**: `.html`, `.htm`, `.css`, `.js`, `.json`, `.xml`, `.yml`
* **Photo**: Activates direct live camera capture interfaces.

{% hint style="info" %}

#### Device-specific responsive upload modes

The widget dynamically adjusts its layout buttons based on the user's operating system and your selected file categories.

On desktop interfaces, it exclusively uses the standard file picker interface. On mobile or tablet devices, selecting only the `Photo` category activates a single camera launch button. Selecting a mix of file categories and `Photo` splits the interface into a two-button layout group, allowing users to choose between picking a file or snapping a photo.
{% endhint %}

### Button configuration

Style the default button appearance directly in the settings panel, or pass a `button` object to override its properties from backend logic at runtime.

| **Property**  | **Description**                                                                                      | **Type** |
| ------------- | ---------------------------------------------------------------------------------------------------- | -------- |
| `text`        | Sets the button text string label.                                                                   | string   |
| `hint`        | Sets the tooltip hover text string.                                                                  | string   |
| `fontSize`    | Sets the size of the button text in pixels.                                                          | integer  |
| `type`        | Sets the color style classification, supporting `default`, `normal`, `success`, `danger`, or `back`. | string   |
| `stylingMode` | Sets the background container rendering type, supporting `text`, `contained`, or `outlined`.         | string   |


# Form

The form widget lets you build dynamic, data-driven forms with a wide variety of input types. Configure the layout, create complex field groups, and connect the widget to backend logic to handle submission, validation, and live updates.

<figure><img src="/files/1nEgLnoNPMyd31ET7nPP" alt="" width="332"><figcaption><p>A form with different editor types</p></figcaption></figure>

## Data binding

### Widget to function input

| **Property**       | **Description**                                                                                                                              | **Type** |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `formData`         | Fires whenever any field value changes. The payload is an object holding all current form data.                                              | object   |
| `validationResult` | Fires after a `validate` command executes. Contains an object describing the validation outcome with `isValid`, `status`, and `brokenRules`. | object   |

### Function output or modifier to widget

| **Property** | **Description**                                                                                                                                                 | **Type**        |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| `autoFill`   | Pre-fills the form with the provided data object. The structure must match the `dataField` names.                                                               | object          |
| `clear`      | Clears all data from the form when set to `true`.                                                                                                               | boolean         |
| `validate`   | Triggers form validation when set to `true`.                                                                                                                    | boolean         |
| `readOnly`   | Sets the read-only state of the entire form when set to `true`.                                                                                                 | boolean         |
| `options`    | Provides options for `select`, `tags`, or `radioGroup` editors at runtime. The object keys must match the `dataField` of the target editor.                     | object          |
| `addFields`  | Adds new fields to the form dynamically. Accepts an array of field objects for a single group, or an object mapping group `dataField` keys to arrays of fields. | array or object |
| `setFields`  | Replaces all existing fields with a new set dynamically. Accepts an array of field objects for a single group, or a full group-structure object.                | array or object |

### Data structure

#### Autofilling the form (`autoFill`)

To pre-fill the form, pass a YAML object to the `autoFill` property. Its structure must mirror your form configuration.

* **Keys**: Keys in your YAML object must match the `dataField` names defined for each field in the configuration.
* **Nesting**: Nest your YAML object to match if you use form groups with a designated `dataField`. The group's `dataField` becomes the key for a nested object holding that group's fields.

**Example configuration:**

```yaml
# personalInfo/
personalInfo:
  firstName: "John"
  lastName: "Doe"
# addressInfo/
addressInfo:
  street: "123 Main St"
  city: "Anytown"
```

The object stays flat if your form configuration uses no groups with `dataField` names:

```yaml
firstName: "John"
lastName: "Doe"
```

#### Setting options at runtime (`options`)

To populate a `select`, `tags`, or `radioGroup` editor at runtime, pass a YAML object to the `options` property.

* **Keys**: Keys of this object must match the `dataField` name of the specific editor you want to update.
* **Values**: The value for each key must be an array of options.

The options in the array support two formats:

1. **Simple array of strings**: Use this format when the display text and the value match. For example: `["Apple", "Banana", "Cherry"]`
2. **Array of key-value pairs**: Use this format when you require different text for display and for the submitted value. Follow the format `["Display Text", "value"]`. For example: `[ ["New York", "NY"], ["California", "CA"] ]`

**Example configuration:**

```yaml
# options/
state:
  - [ "New York", "NY" ]
  - [ "California", "CA" ]
  - [ "Texas", "TX" ]
productTags:
  - "New"
  - "Best Seller"
  - "Clearance"
```

{% hint style="info" %}

#### Extended location field data

When a user selects a place using a `location` editor, the widget adds an extended object to the `formData` payload. The standard field (`dataField`) contains the formatted address string, while a secondary field with an `Ext` suffix (`dataFieldExt`) contains a detailed object with properties like `name`, `address`, `city`, `postcode`, `country`, and `geoJson`.

**Example payload for a location field named `officeAddress`:**

```json
{
  "officeAddress": "One Heisenware Way, Silicon Valley, CA 94043, USA",
  "officeAddressExt": {
    "name": "Heisenware HQ",
    "address": "One Heisenware Way, Silicon Valley, CA 94043, USA",
    "streetName": "Heisenware Way",
    "streetNumber": "1",
    "city": "Silicon Valley",
    "state": "California",
    "country": "United States",
    "postcode": "94043",
    "placeId": "ChIJ...",
    "geoJson": {
      "type": "Point",
      "coordinates": [37.422, -122.084]
    }
  }
}
```

{% endhint %}

## Configuration

### Style settings

These properties control the overall appearance and layout of the form widget.

| **Property**                | **Label**                           | **Description**                                                                          | **Type** |
| --------------------------- | ----------------------------------- | ---------------------------------------------------------------------------------------- | -------- |
| `colCount`                  | Column count                        | Sets the number of columns arranging the form items.                                     | integer  |
| `labelLocation`             | Label location                      | Controls where field labels sit relative to the editors.                                 | string   |
| `labelMode`                 | Label mode                          | Defines how labels display, supporting `static`, `floating`, `hidden`, or `outside`.     | string   |
| `showColonAfterLabel`       | Show colon                          | Adds a colon after each field label when set to `true`.                                  | boolean  |
| `initiallyReadOnly`         | Initially read-only                 | Renders the entire form as read-only when it first loads.                                | boolean  |
| `triggerFormDataOnAutoFill` | Trigger form data event on autofill | Automatically triggers an outgoing `formData` event when an `autoFill` command executes. | boolean  |
| `fontSizeContent`           | Content font size                   | Sets the font size in pixels for text inside the form fields.                            | integer  |
| `fontSizeLabel`             | Label font size                     | Sets the font size in pixels for the field labels.                                       | integer  |

{% hint style="info" %}

#### Screen-specific column layouts

Modify the column count for each screen type separately to display a different number of columns across interfaces. The platform automatically applies other style settings to all screens at once to preserve layout consistency.
{% endhint %}

### Data settings

Define the structure and content of your form by configuring groups and fields.

**Form groups**

Organize your form into one or more groups. With multiple groups, you can optionally display them as tabs.

| **Property** | **Label**        | **Description**                                                                         | **Type** |
| ------------ | ---------------- | --------------------------------------------------------------------------------------- | -------- |
| `dataField`  | Group field name | A unique name for the group. On submit, every field in this group nests under this key. | string   |
| `label`      | Group label      | A visible title displayed above the group of fields.                                    | string   |
| `tabView`    | Tab label        | Groups sharing an identical `tabView` label render as tabs within a tab panel.          | string   |
| `fields`     | Fields           | An array of field objects belonging to this group.                                      | array    |

**Form fields**

Each item in the `fields` array defines an active input editor in your form.

| **Property** | **Label**   | **Description**                                                              | **Type** |
| ------------ | ----------- | ---------------------------------------------------------------------------- | -------- |
| `dataField`  | Field name  | A unique name for the field that serves as the key in the form data object.  | string   |
| `label`      | Label       | The text label displayed for the field editor.                               | string   |
| `helpText`   | Help text   | Hint text to guide the user.                                                 | string   |
| `colSpan`    | Column span | The number of columns the field occupies in the layout.                      | integer  |
| `isRequired` | Required    | Marks the field as mandatory during form validation.                         | boolean  |
| `disabled`   | Disabled    | Disables the field to prevent user interaction.                              | boolean  |
| `readOnly`   | Read-only   | Makes the specific field read-only.                                          | boolean  |
| `editor`     | Editor type | The input control type to render. Supports sixteen different editor options. | string   |

#### Editor types

The `editor` property configuration determines which interface control renders on screen:

| **Editor type** | **Description or value type**                                                    |
| --------------- | -------------------------------------------------------------------------------- |
| `text`          | Text box, outputs a string value.                                                |
| `select`        | Select box, outputs a string selection value.                                    |
| `number`        | Number box, outputs a numeric value.                                             |
| `checkbox`      | Check box, outputs a boolean value.                                              |
| `password`      | Password text box, hides characters and outputs a string value.                  |
| `tags`          | Tag box, outputs an array of selected values.                                    |
| `dateTime`      | Date/time select, outputs a serialized date string.                              |
| `dateRange`     | Date range selector, outputs an array containing date spans.                     |
| `color`         | Color select, outputs a hexadecimal color number.                                |
| `location`      | Location select, provides Google Maps autocompletion to output a geojson object. |
| `radioGroup`    | Radio button group, outputs a string selection value.                            |
| `textarea`      | Text area field, spans multiple lines and outputs a string value.                |
| `slider`        | Range slider, outputs a numeric value.                                           |
| `switch`        | Binary switch toggle, outputs a boolean value.                                   |
| `calendar`      | Inline calendar picker, outputs a selected date value.                           |
| `edgeConnector` | Specialized dropdown that lists available edge-connector data sources.           |

#### Editor-specific configuration options

Configure the specific behavioral parameters of your selected input controllers using the unified options table below.

| **Property**         | **Label**             | **Description**                                                                                                                                   | **Type**                   |
| -------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
| `accentColor`        | Use accent color      | Applies the global theme accent color style (`text` only).                                                                                        | boolean                    |
| `min`                | Minimum               | Sets the minimum allowed numeric boundary value (`number` and `slider` only).                                                                     | number                     |
| `max`                | Maximum               | Sets the maximum allowed numeric boundary value (`number` and `slider` only).                                                                     | number                     |
| `defaultValue`       | Default value         | Defines the initial pre-selected state or fallback content value (`number`, `slider`, `select`, `tags`, `radioGroup`, `switch` only).             | string, number, or boolean |
| `prefix`             | Prefix                | Prepend text formatting before the number string representation (`number` only).                                                                  | string                     |
| `suffix`             | Suffix                | Append text formatting after the number string representation (`number` only).                                                                    | string                     |
| `showSeparator`      | Show separator        | Employs thousands punctuation marks within the text layout representation (`number` only).                                                        | boolean                    |
| `precision`          | Precision             | Enforces a maximum scale count constraint for floating decimal places (`number` only).                                                            | number                     |
| `step`               | Step                  | Defines the strict adjustment interval stepping sequence increment value (`slider` only).                                                         | number                     |
| `options`            | Options               | Comma-separated alternative options layout configurations matching the `display:value` pair structure rule (`select`, `tags`, `radioGroup` only). | string                     |
| `searchEnabled`      | Enable searching      | Grants interactive textual lookup filters functionality over lists (`select` and `edgeConnector` only).                                           | boolean                    |
| `showClearButton`    | Show clear button     | Introduces an interactive clearing icon button utility component structure (`select` only).                                                       | boolean                    |
| `showDropDownButton` | Show drop down button | Toggles structural layout rendering visibility for the dropdown expansion anchor indicator box (`select` and `edgeConnector` only).               | boolean                    |
| `layout`             | Layout                | Dictates explicit positioning configuration structures, allowing `vertically` or `horizontally` options (`radioGroup` only).                      | string                     |
| `switchedOnText`     | Switched on text      | Overrides text layout representations matching active structural states (`switch` only).                                                          | string                     |
| `switchedOffText`    | Switched off text     | Overrides text layout representations matching inactive structural states (`switch` only).                                                        | string                     |
| `dateType`           | Date type             | Configures target structural picker focus formats among `date`, `time`, or `datetime` models (`dateTime` only).                                   | string                     |
| `locationType`       | Location type         | Declares target Google Places endpoint filtering scopes matching `address` or `establishment` classifications (`location` only).                  | string                     |


# Photo

The photo widget lets users capture images with their device camera. The full-screen camera interface provides direct control over aspect ratio and orientation to support photo capture in the field. The widget stores each photo as a physical file on the server or as a Base64-encoded string, and displays a preview list of captured images.

<figure><img src="/files/r2cU1uVyJxTW85cz9OtW" alt=""><figcaption><p>Default view with one photo taken</p></figcaption></figure>

{% hint style="info" %}

#### Alternative photo capture options

The upload widget also captures photos at higher resolutions since v88. Use the photo widget when you require webcams, smaller image sizes, or specific aspect ratios.
{% endhint %}

## Data binding

### Widget to function input

| **Property** | **Description**                                                                                    | **Type** |
| ------------ | -------------------------------------------------------------------------------------------------- | -------- |
| `images`     | Fires when a user takes, saves, or deletes a photo. The payload carries an array of photo objects. | array    |

### Function output or modifier to widget

| **Property** | **Description**                                               | **Type** |
| ------------ | ------------------------------------------------------------- | -------- |
| `images`     | Populates the widget with an existing array of photo objects. | array    |
| `isLoading`  | Displays a loading indicator when `true`.                     | boolean  |
| `button`     | Overrides the capture button configuration at runtime.        | object   |

### Data formats

The structure of the photo objects inside the `images` array depends on your configured storage type.

**File storage payload**

When `storageType` is set to `file`, the payload provides a server path:

```json
{
  "lastModified": 1678886400000,
  "name": "photo-mar-15-2023-120000",
  "type": "image/jpeg",
  "path": "/shared/runtime-files/a1b2c3d4e5.jpeg"
}
```

**Buffer storage payload**

When `storageType` is set to `buffer`, the payload provides a Base64-encoded string:

```json
{
  "lastModified": 1678886400000,
  "name": "photo-mar-15-2023-120000",
  "type": "image/jpeg",
  "base64": "iVBORw0KGgoAAAANSUhEUgA..."
}
```

## Configuration

Set the widget's defaults in the settings panel.

### General settings

| **Property**      | **Label**                | **Description**                                                                                                                  | **Type** |
| ----------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `storageType`     | Storage type             | Controls whether the widget stores each photo as a physical file on the server (`file`) or as a Base64 string (`buffer`).        | string   |
| `aspectRatio`     | Aspect ratio             | Sets the aspect ratio of the camera view. Use `cover` to fill the available screen area.                                         | string   |
| `orientation`     | Orientation              | Dictates the camera capture orientation, supporting `portrait` or `landscape`.                                                   | string   |
| `maxPhotos`       | Maximum number of photos | Sets the total number of photos the widget can hold. The capture button disables automatically when the list reaches this limit. | integer  |
| `resolution`      | Resolution               | Sets the active camera capture resolution quality, supporting `preview`, `balanced`, `high`, or `original`.                      | string   |
| `thumbnailHeight` | Thumbnail size           | Sets the layout height of the preview thumbnails in pixels.                                                                      | number   |

### Button configuration

The widget renders a button to activate the camera interface. Style the default appearance directly in the settings panel, or pass a `button` object to override its properties from backend logic at runtime. The configuration object accepts standard button fields including text, hint, font size, type (`default`, `normal`, `success`, `danger`, `back`), and styling mode (`text`, `contained`, `outlined`).


# Signature

The signature widget captures handwritten signatures as image data. It displays an interactive popup drawing pad that saves user drawings as Base64-encoded strings in your Apps.

<figure><img src="/files/i4HpB6sgxPqvbyFhyJQI" alt=""><figcaption></figcaption></figure>

## Data binding

### Widget to function input

| **Property** | **Description**                                                                                                        | **Type** |
| ------------ | ---------------------------------------------------------------------------------------------------------------------- | -------- |
| `signature`  | Fires when the user clicks the accept button to confirm their signature. The payload carries the signature data block. | string   |

### Data formats

The widget extracts drawing coordinates from the pad canvas and outputs them as a clean, compressed image string.

**Signature payload** The payload returns a raw Base64-encoded PNG string, stripped of the standard browser `data:image/png;base64,` schema prefix for direct compatibility with backend file processing blocks: `"iVBORw0KGgoAAAANSUhEUgAAAZAAAADICAQAA..."`

## Configuration

Set the widget's defaults in the settings panel.

### General settings

| **Property**  | **Label**    | **Description**                                                                                                                  | **Type** |
| ------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `displayMode` | Display mode | Controls the display architecture of the pad layout. Currently supports `popup` mode to render an activation button on the page. | string   |
| `buttonText`  | Button text  | The text label printed on the main widget activation button when display mode is set to popup.                                   | string   |
| `acceptText`  | Accept text  | The text label printed on the signature validation button inside the popup frame.                                                | string   |
| `clearText`   | Clear text   | The text label printed on the pad clearing button inside the popup frame.                                                        | string   |
| `penColor`    | Pen color    | Sets the ink trace stroke color on the sketch area. Defaults to the global theme text color when gray.                           | string   |
| `padColor`    | Pad color    | Sets the solid background color of the drawing canvas area.                                                                      | string   |
| `width`       | Width        | Sets the layout width dimension of the activation button in pixels.                                                              | integer  |
| `height`      | Height       | Sets the layout height dimension of the activation button in pixels.                                                             | integer  |

## Tips and tricks

{% hint style="info" %}

#### Display layout limitations and drawing bounds

The current version of the widget requires the display mode parameter configured strictly as `popup`. Setting this value to inline prevents the workspace frame from rendering entirely.

While the activation button respects your configured height and width options, the pop-up drawing pad automatically enforces a fixed, clear bounds of 400x200 pixels to optimize touch responsiveness across mobile and desktop interfaces.
{% endhint %}


# Trigger widgets

Trigger widgets capture direct user actions, such as clicks, to execute backend logic.

## Available trigger widgets

* [**Button**](/app-builder/build-frontend/widgets/trigger-widgets/button): Captures clicks to execute function sequences.

{% hint style="info" %}

#### Using icons as triggers

The button is the primary widget in this category, but you can also configure [icons](/app-builder/build-frontend/text-icons-and-images#icons) as triggers. Icons follow identical data binding rules.
{% endhint %}

## Data binding

Drag from a function or modifier onto the button. The selected slot determines the behavior:

* **Button to function trigger**: A click executes the connected function. The trigger transmits no data. This is the primary direction for trigger widgets.
* **Function output or modifier to widget**: A function output or modifier writes back into a button property. For example, link an output to the `done` property of a [button](/app-builder/build-frontend/widgets/trigger-widgets/button) to display a loading animation until that segment of the flow finishes.

The button features a single `onClick` event, so the selection happens automatically when linking a trigger. See [Widgets](/app-builder/build-frontend/widgets#data-binding) for the full mechanics.

{% hint style="info" %}

#### Auto-triggering on input

To execute a function automatically from user interface input instead of a click, wire the input of the function to its own trigger. The incoming data feeds and executes the function without requiring a button widget.
{% endhint %}


# Button

The button widget captures a user click to trigger backend logic. You can also drive its appearance and operational state from your logic to provide live visual feedback.

## Data binding

### Widget to function trigger

| **Property** | **Description**                                                                                                         | **Type** |
| ------------ | ----------------------------------------------------------------------------------------------------------------------- | -------- |
| `onClick`    | Fires when a user clicks the button to start a backend process. Sends a pure trigger with no accompanying data payload. | trigger  |

### Widget to function input

| **Property** | **Description**                                                                                                  | **Type** |
| ------------ | ---------------------------------------------------------------------------------------------------------------- | -------- |
| `onClick`    | Fires when a user clicks the button and passes the configured button text string directly into a function input. | string   |

### Function output or modifier to widget

| **Property** | **Description**                                                                                                                                                       | **Type** |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `disable`    | Disables the button and prevents user interactions when `true`.                                                                                                       | boolean  |
| `enable`     | Enables the button when `true`. Use this to re-enable a button that starts as initially disabled.                                                                     | boolean  |
| `toggle`     | Dynamically enables or disables the button based on the incoming boolean value.                                                                                       | boolean  |
| `done`       | Displays an active loading indicator on the button when connected to a running function. The loading state clears automatically when the function returns its output. | any      |

## Configuration

Set the widget's defaults in the settings panel.

### General settings

| **Property**           | **Label**             | **Description**                                                                                                                                   | **Type** |
| ---------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `text`                 | Text                  | Sets the text label displayed on the button.                                                                                                      | string   |
| `icon`                 | Icon                  | Adds a visual icon to the left of the button text.                                                                                                | string   |
| `fontSize`             | Text size             | Sets the font size of the button text label in pixels.                                                                                            | integer  |
| `iconSize`             | Icon size             | Sets the layout size of the button icon in pixels.                                                                                                | integer  |
| `type`                 | Type                  | Controls the button color scheme configuration based on the theme, supporting `default`, `normal`, `success`, `danger`, `back`, or `transparent`. | string   |
| `stylingMode`          | Styling mode          | Controls the visual container rendering style, supporting `text`, `contained`, or `outlined`.                                                     | string   |
| `hint`                 | Hover text            | Sets the tooltip text displayed when a user hovers over the button.                                                                               | string   |
| `disabled`             | Initially disabled    | Disables the button when the App first loads when set to `true`.                                                                                  | boolean  |
| `requiresConfirmation` | Requires confirmation | Opens an interactive confirmation modal dialog before executing actions when set to `true`.                                                       | boolean  |
| `confirmationTitle`    | Confirmation title    | Sets the title text displayed on the confirmation modal dialog.                                                                                   | string   |
| `confirmationText`     | Confirmation text     | Sets the main description message displayed inside the confirmation modal dialog.                                                                 | string   |
| `reload`               | Reload                | Reloads the active App automatically upon a user click when set to `true`.                                                                        | boolean  |
| `width`                | Width                 | Sets the layout width dimension of the button in pixels.                                                                                          | integer  |
| `height`               | Height                | Sets the layout height dimension of the button in pixels.                                                                                         | integer  |

## Tips and tricks

{% hint style="info" %}

#### Making specific user interface areas clickable

Use transparent buttons to capture user clicks on specific areas of your layout and pass contextual information directly into your logic. This configuration lets you build interactive visual maps.

For example, upload an image of your shopfloor and position a transparent button over a specific machine asset. Set the button text to match the unique machine asset ID. Selecting the `transparent` type keeps the text completely hidden from the view. When a user clicks that area of the image, the button passes the ID into your logic via the `onClick` property to execute filtered data navigation or page routing.
{% endhint %}


# Display widgets

Display widgets render data as charts, gauges, maps, and tables. These components receive values from functions and modifiers to display them live, forming the core building blocks of dashboards and data-driven interfaces.

{% hint style="info" %}

#### Widget versatility and categorization

The platform groups widgets by their primary purpose, though many serve multiple roles. For example, a [form](/app-builder/build-frontend/widgets/input-widgets/form) (an [input widget](/app-builder/build-frontend/widgets/input-widgets)) can display data and a [data grid](/app-builder/build-frontend/widgets/display-widgets/data-grid) (a [display widget](/app-builder/build-frontend/widgets/display-widgets)) can capture input. Check the properties of each widget to see its full capabilities.
{% endhint %}

## Available display widgets

* [**Card**](/app-builder/build-frontend/widgets/display-widgets/card): Groups and structures other layout elements.
* [**Chart**](/app-builder/build-frontend/widgets/display-widgets/chart): Renders line, bar, area, and scatter charts.
* [**Chat**](/app-builder/build-frontend/widgets/display-widgets/chat): Provides a conversational interface for RAG use cases.
* [**Circular gauge**](/app-builder/build-frontend/widgets/display-widgets/circular-gauge): Displays a primary value and a secondary sub-value on a circular dial.
* [**Data grid**](/app-builder/build-frontend/widgets/display-widgets/data-grid): Displays database records in an interactive table that supports viewing and editing.
* [**Data list**](/app-builder/build-frontend/widgets/display-widgets/data-list): Displays a scrollable list of items.
* [**Data tiles**](/app-builder/build-frontend/widgets/display-widgets/data-tiles): Arranges items into responsive tile layouts.
* [**Dynamic group**](/app-builder/build-frontend/widgets/dynamic-group): Bundles multiple widgets together to act as a repeated container driven by data.
* [**Iframe**](/app-builder/build-frontend/widgets/display-widgets/iframe): Embeds external web pages or applications inside the interface.
* [**Kanban**](/app-builder/build-frontend/widgets/display-widgets/kanban): Arranges items on an interactive board to track process stages.
* [**Linear gauge**](/app-builder/build-frontend/widgets/display-widgets/linear-gauge): Displays a primary value and a secondary sub-value on a linear bar.
* [**Map**](/app-builder/build-frontend/widgets/display-widgets/map): Displays geographic data points on an interactive map.
* [**Media view**](/app-builder/build-frontend/widgets/display-widgets/media-view): Displays images, videos, or PDF files dynamically.
* [**Pie chart**](/app-builder/build-frontend/widgets/display-widgets/pie-chart): Displays proportional data as parts of a whole.
* [**Progress bar**](/app-builder/build-frontend/widgets/display-widgets/progress-bar): Displays process progress as a percentage or an absolute value.
* [**Sankey**](/app-builder/build-frontend/widgets/display-widgets/sankey): Displays the flow and distribution of values between datasets.
* [**Sparkline**](/app-builder/build-frontend/widgets/display-widgets/sparkline): Displays a compact line chart without axes to show inline trends.
* [**Status lamp**](/app-builder/build-frontend/widgets/display-widgets/status-lamp): Displays operational status using a colored light indicator.
* [**Timeline**](/app-builder/build-frontend/widgets/display-widgets/timeline): Displays state changes over a time span, such as machine production and downtime phases.
* [**Toast**](/app-builder/build-frontend/widgets/display-widgets/toast): Displays brief temporary notifications.
* [**Value box**](/app-builder/build-frontend/widgets/display-widgets/value-box): Displays a single key figure or individual content block.

## Data binding

Display widgets receive data from functions and modifiers. Drag from a function or modifier onto the widget. The selected slot determines the data direction:

* **Function output or modifier to widget**: A function output or modifier writes into a widget property, such as a time series array feeding into a chart data property. This is the primary direction for display widgets.
* **Widget to function input**: Certain display widgets, such as the data grid, send data back to backend logic. A widget event flows into a function input along with its data payload, transmitting edited cells or selected rows the moment they change.

See [Widgets](/app-builder/build-frontend/widgets#data-binding) for the full mechanics.


# Card

The card widget is a decorative container that structures and groups other widgets on the canvas of your App. It provides a background surface driven by styling data such as colors, borders, and shadows.

## Data binding

### Function output or modifier to widget

| **Property**      | **Description**                                                                                                     | **Type**         |
| ----------------- | ------------------------------------------------------------------------------------------------------------------- | ---------------- |
| `width`           | Sets the horizontal width of the card.                                                                              | string or number |
| `height`          | Sets the vertical height of the card.                                                                               | string or number |
| `variant`         | Switches the surface style between `elevation` (shadow-based) and `outlined` (border-based).                        | string           |
| `backgroundColor` | Sets the background color of the card.                                                                              | string           |
| `opacity`         | Sets the transparency of the widget from `0.0` (fully transparent) to `1.0` (opaque).                               | number           |
| `borderRadius`    | Sets the corner rounding radius. Use `theme` to match the global app styles.                                        | string           |
| `elevation`       | Sets the shadow depth (`flat`, `theme`, `low`, `medium`, `high`) when `variant` is set to `elevation`.              | string           |
| `border`          | Sets the border properties when `variant` is set to `outlined`. Takes an object with `width`, `style`, and `color`. | object           |
| `style`           | An array of custom CSS property objects containing `key` and `value` pairs for advanced styling overrides.          | array\<object>   |

## Configuration

Set the widget's defaults in the settings panel.

### Card style

| **Property** | **Label**       | **Description**                                                                                        | **Type** |
| ------------ | --------------- | ------------------------------------------------------------------------------------------------------ | -------- |
| `variant`    | Surface style   | Choose elevation for shadows or outlined for borders.                                                  | string   |
| `elevation`  | Elevation       | Sets the shadow depth from flat to high. This field is visible when surface style is set to elevation. | string   |
| `border`     | Border settings | Sets the border width, color, and style. This field is visible when surface style is set to outlined.  | object   |

### Styling and customization

| **Property**      | **Label**        | **Description**                                 | **Type** |
| ----------------- | ---------------- | ----------------------------------------------- | -------- |
| `backgroundColor` | Background color | Sets the background color of the card.          | string   |
| `opacity`         | Opacity          | Sets the transparency of the card from 0 to 1.  | number   |
| `borderRadius`    | Corner radius    | Sets the corner rounding from square to circle. | string   |

### Custom CSS overrides

| **Property** | **Label** | **Description**                  | **Type** |
| ------------ | --------- | -------------------------------- | -------- |
| `key`        | Property  | The camelCase CSS property name. | string   |
| `value`      | Value     | The matching CSS property value. | string   |


# Chart

The chart widget displays data arrays as line, bar, area, scatter, bubble, or financial charts. It visualizes complex datasets across multiple customizable panes, axes, and series to build interactive dashboards.

<figure><img src="/files/wjuZU58yF35KZ0N9RAlN" alt=""><figcaption><p>All types of single-series chart</p></figcaption></figure>

<figure><img src="/files/3xJnSuDZLcfjmta9GUZ3" alt=""><figcaption></figcaption></figure>

## Data binding

### Function output or modifier to widget

| **Property**    | **Description**                                                                                                                                                                                | **Type**       |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `data`          | An array of data objects or values to plot on the chart. The chart automatically flattens nested objects using a hyphen delimiter (for example, `sensor: { temp: 21 }` becomes `sensor-temp`). | array          |
| `constantLines` | An array of dynamic constant lines fed from the backend to display indicator lines across matching axis indices.                                                                               | array\<object> |

#### Automatic configuration

Feed data to the widget without defining any series in the data settings, and it configures itself. It reads the data to find the most likely `argumentField` and `valueField`, creates a default series, and fills the configuration panel with what it detected, ready for you to customize further.

## Configuration

Set the widget's defaults in the settings panel.

### Chart settings

| **Property**           | **Label**               | **Description**                                                                                                                                      | **Type** |
| ---------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `showTooltips`         | Show value tooltips     | Displays a detailed informational popup when hovering over a data point. Formats dates and numbers automatically based on system locale.             | boolean  |
| `zoomAndPan`           | Zoom and pan            | Controls chart interactivity. Set to `enabled` (always active), `selectable` (adds an on-chart button to lock scrolling and unlock zoom), or `none`. | string   |
| `scaleToConstantLines` | Scale to constant lines | Adds an 8% padding margin to the top and bottom of the value scales to prevent constant line labels from clipping.                                   | boolean  |
| `adjustOnZoom`         | Adjust on zoom          | Recalculates the value axis range dynamically when zooming into an argument range.                                                                   | boolean  |
| `autoHidePointMarkers` | Auto hide point markers | Hides point markers automatically when the density of data points clutters the view.                                                                 | boolean  |
| `enableCrosshair`      | Enable crosshair        | Displays crosshair tracking lines that follow the user cursor to map intersections on the axes.                                                      | boolean  |
| `negativesAsZeroes`    | Negatives as zeroes     | Treats all negative values in the dataset as zero.                                                                                                   | boolean  |
| `rotated`              | Rotated                 | Swaps the horizontal argument axis and the vertical value axis layouts.                                                                              | boolean  |
| `disabled`             | Disabled                | Disables all hover, zoom, pan, and click interactions on the chart canvas.                                                                           | boolean  |
| `pointSelectionMode`   | Point selection mode    | Determines whether users can select a `single` point or `multiple` points.                                                                           | string   |
| `seriesSelectionMode`  | Series selection mode   | Determines whether users can select a `single` series or `multiple` series.                                                                          | string   |
| `barGroupPadding`      | Bar group padding       | Controls the spacing between distinct groups of bars in a bar chart.                                                                                 | number   |
| `barGroupWidth`        | Bar group width         | Enforces a fixed pixel width for groups of bars.                                                                                                     | number   |
| `palette`              | Palette                 | An array of custom hex color codes used sequentially to paint chart series.                                                                          | array    |
| `defaultPane`          | Default pane            | Names the primary pane used when no explicit pane assignment is configured on a series.                                                              | string   |

### Value axes settings

Configure the value axes for the chart. You can add multiple axes and distribute them across different layout panes.

| **Property**      | **Label**      | **Description**                                                                                                 | **Type**       |
| ----------------- | -------------- | --------------------------------------------------------------------------------------------------------------- | -------------- |
| `title`           | Title          | The text label displayed alongside the axis line.                                                               | string         |
| `position`        | Position       | Positions the axis relative to the pane area (`left`, `right`, `top`, `bottom`).                                | string         |
| `width`           | Axis width     | Sets the line thickness of the axis in pixels.                                                                  | integer        |
| `color`           | Color          | Sets the color of the axis line.                                                                                | string         |
| `fixedStartValue` | Start value    | Enforces a hard starting limit for the axis range, overriding automatic calculations.                           | number         |
| `fixedEndValue`   | End value      | Enforces a hard ending limit for the axis range, overriding automatic calculations.                             | number         |
| `visible`         | Visible        | Toggles the visibility of the entire axis line.                                                                 | boolean        |
| `endOnTick`       | End on tick    | Forces the axis scale boundary to snap perfectly to a major tick mark.                                          | boolean        |
| `inverted`        | Inverted       | Flips the direction of values along the scale.                                                                  | boolean        |
| `label`           | Label          | Configuration object for axis labels, including `visible`, `fontSize`, `fontWeight`, `fontColor`, and `format`. | object         |
| `grid`            | Grid and ticks | Configuration object managing major and minor grid lines, line colors, and tick visibility.                     | object         |
| `constantLines`   | Constant lines | An array of static indicator lines to draw across this axis, supporting custom labels, dash styles, and colors. | array\<object> |

### Argument axis settings

Configure the axis representing your independent variable (usually the horizontal X-axis).

| **Property**           | **Label**            | **Description**                                                                       | **Type** |
| ---------------------- | -------------------- | ------------------------------------------------------------------------------------- | -------- |
| `titleX`               | Title                | The text label displayed underneath or beside the argument axis.                      | string   |
| `argumentTypeX`        | Argument type        | Dictates the data scale type (`numeric`, `datetime`, `string`).                       | string   |
| `widthX`               | Axis width           | Sets the line thickness of the axis line in pixels.                                   | integer  |
| `colorX`               | Color                | Sets the color of the axis line.                                                      | string   |
| `visibleX`             | Visible              | Toggles the visibility of the argument axis line.                                     | boolean  |
| `endOnTickX`           | End on tick          | Forces the argument axis scale boundary to snap perfectly to a major tick mark.       | boolean  |
| `invertedX`            | Inverted             | Reverses the horizontal or vertical progression direction of the arguments.           | boolean  |
| `intervalUnitX`        | Tick interval unit   | Sets the date-time unit size (`days`, `months`, `hours`) for tick generation.         | string   |
| `intervalX`            | Tick interval        | The step multiplier between major tick marks based on the selected unit.              | integer  |
| `aggregationUnitX`     | Aggregation unit     | The date-time unit size used to group dense raw points into summary intervals.        | string   |
| `aggregationIntervalX` | Aggregation interval | The step multiplier defining the duration of each summary interval group.             | integer  |
| `labelX`               | Label                | Configuration object for layout spacing, text formatting, and font styling of labels. | object   |
| `gridX`                | Grid and ticks       | Toggles visibility and colors for major/minor grids and physical ticks.               | object   |

### Legend settings

| **Property**                | **Label**            | **Description**                                                                                    | **Type** |
| --------------------------- | -------------------- | -------------------------------------------------------------------------------------------------- | -------- |
| `legendVisible`             | Visible              | Toggles the visibility of the series legend block.                                                 | boolean  |
| `legendTitle`               | Title                | The main header string shown inside the legend bounding box.                                       | string   |
| `legendSubtitle`            | Subtitle             | Secondary text positioned directly below the legend title.                                         | string   |
| `legendVerticalAlignment`   | Vertical alignment   | Snaps the legend block vertically to the `top` or `bottom`.                                        | string   |
| `legendHorizontalAlignment` | Horizontal alignment | Snaps the legend block horizontally to the `left`, `center`, or `right`.                           | string   |
| `legendItemTextPosition`    | Item text position   | Controls whether item labels sit to the `left`, `right`, `top`, or `bottom` of their color marker. | string   |
| `legendPosition`            | Position             | Places the entire legend block `inside` or `outside` the active chart plotting pane.               | string   |
| `legendOrientation`         | Orientation          | Lays out the legend items `horizontally` or `vertically`.                                          | string   |
| `legendFont`                | Font settings        | Styling configuration object managing legend text size, weight, and color.                         | object   |

### Data settings

| **Property**    | **Label**      | **Description**                                                             | **Type**       |
| --------------- | -------------- | --------------------------------------------------------------------------- | -------------- |
| `argumentField` | Argument field | The object key path in your data array providing the base axis coordinates. | string         |
| `seriesData`    | Series data    | An array of series mapping configurations detailing individual plots.       | array\<object> |

#### Series properties

Each object inside the `seriesData` configuration array supports these properties:

| **Property**        | **Label**           | **Description**                                                                                               | **Type** |
| ------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------- | -------- |
| `pane`              | Pane                | Assigns this specific data series to a designated chart layout pane.                                          | string   |
| `name`              | Series name         | The display label for this series inside tooltips and the legend block.                                       | string   |
| `valueField`        | Value field         | The object key path in your data array providing the primary Y-axis values.                                   | string   |
| `type`              | Series type         | The chart visualization type (such as `line`, `bar`, `area`, `scatter`, `bubble`, `rangebar`, `candlestick`). | string   |
| `axis`              | Value axis          | Associates the series with a specific named value axis.                                                       | string   |
| `aggregation`       | Aggregation         | The downsampling function applied when data is clustered (`avg`, `min`, `max`, `sum`, `count`).               | string   |
| `pointSymbol`       | Data points         | Defines the geometric shape marking points on lines or areas (`circle`, `square`, `triangle`, `none`).        | string   |
| `color`             | Custom color        | Overrides the global color palette with a specific hex color code for this plot.                              | string   |
| `tagField`          | Tag field           | Key path to a data property whose string value gets appended as a highlighted header tag inside the tooltip.  | string   |
| `ignoreEmptyPoints` | Ignore empty points | Connects lines across missing or null data gaps instead of leaving empty canvas breaks.                       | boolean  |
| `rangeValue1Field`  | Range value 1       | Specifies the starting boundary key for range charts (`rangearea`, `rangebar`).                               | string   |
| `rangeValue2Field`  | Range value 2       | Specifies the ending boundary key for range charts (`rangearea`, `rangebar`).                                 | string   |
| `sizeField`         | Size field          | Specifies the key determining bubble diameter calculations in bubble charts.                                  | string   |
| `openValueField`    | Open value field    | Maps the opening value key for financial stock tracking layouts.                                              | string   |
| `closeValueField`   | Close value field   | Maps the closing value key for financial stock tracking layouts.                                              | string   |
| `highValueField`    | High value field    | Maps the maximum threshold value key for financial stock tracking layouts.                                    | string   |
| `lowValueField`     | Low value field     | Maps the minimum threshold value key for financial stock tracking layouts.                                    | string   |

## Tips and tricks

### Reading nested data objects

The chart automatically flattens complex data structures passed into `data`. If your backend payload contains nested objects, access deep keys by substituting hyphens for the object path. For example, a structure like `sensor: { temp: 21 }` becomes `sensor-temp`.

### Multi-series charts

To show several data series on one chart (comparing temperature and humidity over time, for example), the chart needs a specific data format. You cannot plug in separate arrays; you must combine them into a single array of objects where each object shares a common argument like a timestamp.

#### Prepare the data

Combine your data arrays using a combine function node inside the Backend Builder. Then, append a JavaScript modifier node to the output. This code merges the two datasets by timestamp, producing a list of objects with `date`, `value1` (from the first array), and `value2` (from the second):

```js
// 'x' represents the input array containing your two datasets
Array.from(new Set((x[0] || []).concat(x[1] || []).map(i => i.date)))
  .sort()
  .map(d => ({
    date: d,
    // Find value in first dataset, or return null if missing
    value1: (x[0] || []).find(i => i.date === d)?.value ?? null,
    // Find value in second dataset, or return null if missing
    value2: (x[1] || []).find(i => i.date === d)?.value ?? null
  }))
```

If your data uses different field names (like `timestamp` instead of `date`), adjust the property names in the code to match.

#### The required data structure

After the modifier node, your data uses this structure. Some values are `null`, which is normal: it happens when a timestamp exists in one dataset but not the other (such as when sensors record at slightly different milliseconds):

```json
[
  { "date": "2026-10-27T10:00:01Z", "value1": 25.5, "value2": null },
  { "date": "2026-10-27T10:00:02Z", "value1": 25.6, "value2": 60.2 },
  { "date": "2026-10-27T10:00:03Z", "value1": null, "value2": 60.1 }
]
```

#### Configure the chart

1. Connect the modifier node output to the chart `data` property.
2. Enable ignore empty points for series 1, so the chart bridges `null` points instead of breaking the line.
3. Add a second series under `seriesData`, bind it to `value2`, and enable ignore empty points there too.

The chart now displays both lines on the same time axis, bridging any gaps from mismatched timestamps.

#### Video walkthrough

{% embed url="<https://www.youtube.com/watch?v=bB2iL4SBEiM>" %}

### Optimizing for large datasets

With thousands of data points, rendering performance becomes a concern. The most effective fix is data aggregation. Instead of plotting every point, the chart groups your data into intervals (days, weeks, months) and shows a single aggregated point per interval (the average, sum, min, or max).

To enable aggregation:

* **Set the series aggregation**: In the series properties under `seriesData`, set the aggregation method to `avg`, `sum`, `min`, or `max`.
* **Configure the argument axis**: In the argument axis settings, set the aggregation unit (such as `days`) and the aggregation interval (such as `7` for weekly groupings).

### Enhancing the user experience

* **Zooming and panning**: The chart supports zooming and panning out of the box. Users drag to select a region to zoom into and scroll the mouse wheel to zoom in and out. This pairs well with aggregation, as zooming in reveals more granular, non-aggregated data.
* **Intelligent markers**: On dense line or area charts, a marker on every point clutters the view. Turn on auto hide point markers in the chart settings to hide them automatically; they reappear when the user zooms in.
* **Tooltips and crosshairs**: Enable show value tooltips to give users precise values on hover. To compare values across multiple series at the same argument coordinate, enable the crosshairs. Configuring a tag field in your series data adds rich, contextual information to the tooltips.
* **Interacting with the chart**: On desktop, zoom by scrolling with a mouse or trackpad. Placing the cursor directly on an axis zooms that dimension only, leaving the other unchanged. Placing the cursor inside the pane zooms without warping, centering on the cursor. On touch devices, zoom using spread and pinch gestures, and pan with a drag gesture.
* **Interactivity controls**: When setting `zoomAndPan` to `selectable`, an interactive toggle button appears in the top-right corner of the canvas:
  * **Lock to scroll (Search icon)**: Disables chart zooming. Mouse wheels and touch drags scroll the page layout normally.
  * **Unlock to zoom (Lock icon)**: Intercepts mouse wheels, pinch gestures, and click-drags to zoom into chart values. The rest of the App screen stays locked in place.


# Chat

For now, the chat widget works only together with [RAG](/app-builder/build-backend/functions/extensions/rag-ai), letting users chat with uploaded documents and other knowledge sources.

{% hint style="info" %}
This feature is currently in beta. [Reach out to us](mailto:support@heisenware.com) if you want to use it, we're happy to help.
{% endhint %}


# Circular gauge

The circular gauge widget displays numeric values and secondary benchmarks on a radial scale. It visualizes measurements, operational progress, or key performance indicators on your dashboards.

<div align="center"><figure><img src="/files/O2pM5XIevdyXt5s3lhdX" alt="" width="281"><figcaption></figcaption></figure></div>

## Data binding

### Function output or modifier to widget

| **Property**               | **Description**                                                                                   | **Type**       |
| -------------------------- | ------------------------------------------------------------------------------------------------- | -------------- |
| `value`                    | Sets the main indicator pointer value on the radial scale.                                        | number         |
| `subValue`                 | Sets a single secondary value pointer coordinate. If defined, it overrides the `subvalues` array. | number         |
| `subvalues`                | An array of secondary values to plot multiple subvalue indicators simultaneously.                 | array\<number> |
| `disabled`                 | Toggles whether user interactions and tooltips are disabled.                                      | boolean        |
| `containerBackgroundColor` | Sets the solid background fill color of the gauge bounding box.                                   | string         |
| `animation`                | Configures gauge movement animations, accepting an object with `enabled` and `duration`.          | object         |
| `tooltip`                  | Controls contextual hover tooltips, accepting an object with `enabled`.                           | object         |
| `frame`                    | Overrides the geometry layout, ranges, and background color profiles at runtime.                  | object         |
| `scale`                    | Overrides scale boundaries, intervals, and labels at runtime.                                     | object         |
| `valueIndicator`           | Overrides properties for the primary pointer style at runtime.                                    | object         |
| `subvalueIndicator`        | Overrides properties for the secondary pointer style at runtime.                                  | object         |

## Configuration

Set the widget's defaults in the settings panel.

### General settings

| **Property**               | **Label**                  | **Description**                                                                                    | **Type** |
| -------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------- | -------- |
| `containerBackgroundColor` | Container background color | Sets the solid background fill color of the gauge canvas area.                                     | string   |
| `disabled`                 | Disabled                   | Disables all animations, hover tracking highlights, and tooltips when checked.                     | boolean  |
| `animation`                | Animation                  | Configuration object managing pointer motion, supporting nested `enabled` and `duration` controls. | object   |
| `tooltip`                  | Tooltip                    | Configuration object managing hover information popups, supporting an `enabled` toggle.            | object   |

### Frame

These settings control the structural layout and radial architecture of the gauge wheel.

<div align="center"><figure><img src="/files/4l9XRsi4APhFFna3RrFf" alt="" width="375"><figcaption><p>Visual explanation of the properties <code>startAngle</code> and <code>endAngle</code></p></figcaption></figure></div>

| **Property**      | **Label**        | **Description**                                                                                    | **Type** |
| ----------------- | ---------------- | -------------------------------------------------------------------------------------------------- | -------- |
| `startAngle`      | Start angle      | The angle in degrees where the gauge scale progression begins.                                     | integer  |
| `endAngle`        | End angle        | The terminal angle profile mapping where the scale progression stops.                              | integer  |
| `width`           | Frame width      | The line stroke thickness of the circular gauge ring track in pixels.                              | integer  |
| `backgroundColor` | Background color | The background fill color of the frame track container.                                            | string   |
| `ranges`          | Color sections   | An array of threshold range objects used to draw color-coded status warning zones along the frame. | array    |

<div align="center"><figure><img src="/files/DsLvaR7uUeRFg8uS2bkb" alt="" width="563"><figcaption><p>A circular gauge with adjusted frame</p></figcaption></figure></div>

### Scale

Configure the numeric values, tick increments, and text formatting rules driving the scale context.

| **Property** | **Label**   | **Description**                                                 | **Type** |
| ------------ | ----------- | --------------------------------------------------------------- | -------- |
| `startValue` | Start value | The minimum mathematical boundary of the scale.                 | number   |
| `endValue`   | End value   | The maximum mathematical boundary of the scale.                 | number   |
| `label`      | Label       | Configuration object governing the numeric text labels.         | object   |
| `tick`       | Major tick  | Configuration object governing the primary division ticks.      | object   |
| `minorTick`  | Minor tick  | Configuration object governing the secondary subdivision ticks. | object   |

### Scale label and tick properties

These fields manage text formatting and tick distribution parameters nested inside the `label`, `tick`, and `minorTick` blocks.

| **Property** | **Label**   | **Description**                                                                                                         | **Type** |
| ------------ | ----------- | ----------------------------------------------------------------------------------------------------------------------- | -------- |
| `visible`    | Visible     | Toggles the layout visibility of the respective labels or tick strokes on the wheel.                                    | boolean  |
| `size`       | Font size   | (`label` only) Sets the font text size of the numeric tracking characters.                                              | integer  |
| `weight`     | Font weight | (`label` only) Sets the typographical font thickness weight profile (such as `400` for regular or `700` for bold text). | integer  |
| `color`      | Font color  | (`label` only) Sets the color of the scale label digits.                                                                | string   |
| `interval`   | Interval    | (`tick` and `minorTick` only) The step multiplier interval sequence dividing axis markers.                              | number   |
| `length`     | Length      | (`tick` and `minorTick` only) The total pixel line length of the tick lines.                                            | integer  |
| `width`      | Width       | (`tick` and `minorTick` only) The line stroke width thickness of the individual tick lines.                             | integer  |

### Indicator

Manage the pointers representing active metrics on the scale wheel.

<figure><img src="/files/5mdEO3rv8XKtj7kwVSxt" alt=""><figcaption><p>Indicator types (top-left to bottom-right):<br><code>rectangleNeedle, twoColorNeedle, triangleNeedle, rangeBar, triangleMarker, textCloud</code></p></figcaption></figure>

| **Property**        | **Label**          | **Description**                                                                    | **Type** |
| ------------------- | ------------------ | ---------------------------------------------------------------------------------- | -------- |
| `valueIndicator`    | Primary indicator  | Configuration object defining the layout style for the main value pointer.         | object   |
| `subvalueIndicator` | Subvalue indicator | Configuration object defining the layout style for the secondary subvalue pointer. | object   |

### Indicator properties

These configuration fields apply inside both the `valueIndicator` and `subvalueIndicator` parent blocks.

| **Property**       | **Label**                                                                                         | **Description**                                                                                                                                       | **Type** |
| ------------------ | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `type`             | Indicator type                                                                                    | The pointer layout shape style (options include `rectangleNeedle`, `twoColorNeedle`, `triangleNeedle`, `rangeBar`, `triangleMarker`, or `textCloud`). | string   |
| `width`            | Width                                                                                             | The base structural thickness of the indicator pointer.                                                                                               | integer  |
| `offset`           | Scale offset                                                                                      | The physical pixel displacement air gap between the pointer and the scale circle line.                                                                | number   |
| `color`            | Color                                                                                             | The primary hex color code used to paint the pointer structure.                                                                                       | string   |
| `indentFromCenter` | Indent from center                                                                                | Dictates center-pin hub clearance parameters for needle pointer styles.                                                                               | number   |
| `spindleSize`      | Spindle size                                                                                      | Sets the central anchor core radius when using needle styles.                                                                                         | integer  |
| `spindleGapSize`   | Spindle gap size                                                                                  | Sets the core interior tracking clearance gap when using needle styles.                                                                               | integer  |
| `secondColor`      | Second color                                                                                      | Defines the distinct tip trim color accent when `type` is set to `twoColorNeedle`.                                                                    | string   |
| Second fraction    | The proportional length split coordinate determining where the color flips on a `twoColorNeedle`. | number                                                                                                                                                |          |
| `size`             | Size                                                                                              | Enforces the tracking arc thickness dimension strictly when `type` is configured as a `rangeBar`.                                                     | number   |
| `baseValue`        | Base value                                                                                        | The origin tracking base value from which a `rangeBar` arc grows.                                                                                     | number   |
| `length`           | Length                                                                                            | Sets the total length factor profile when utilizing a `triangleMarker`.                                                                               | integer  |
| `arrowLength`      | Arrow length                                                                                      | Sets the extension tail structural length when displaying a callout `textCloud`.                                                                      | integer  |


# Data grid

The data grid widget displays tabular data inside a flexible, interactive table layout. It provides an interface to sort, filter, group, edit, and export large datasets across your Apps.

<figure><img src="/files/NNRA9sSLUmq8M3pCO2Ix" alt=""><figcaption><p>A fully featured data grid with sorting, filtering, grouping, editing, exporting, and a master-detail view.</p></figcaption></figure>

## Data binding

### Function output or modifier to widget

| **Property**         | **Description**                                                                             | **Type**       |
| -------------------- | ------------------------------------------------------------------------------------------- | -------------- |
| `data`               | The primary array of data objects or records to populate within the table grid rows.        | array\<object> |
| `rowFilter`          | Applies a row-level column filter matching criteria directly from backend logic.            | object         |
| `headerFilter`       | Applies a selection list filtering rule to designated column header paths.                  | object         |
| `rowFilterOperation` | Dictates matching operations (such as contains or equals) enforced across your row filters. | object         |

### Widget to function input

| **Property**        | **Description**                                                                                                                                            | **Type**                 |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
| `onChange`          | Fires when a row is updated, sending the modified values along with the row identifier.                                                                    | object                   |
| `onInsert`          | Fires when a user inserts a new record row, sending the newly created data object.                                                                         | object                   |
| `onDelete`          | Fires when a row record is deleted, sending the unique primary key identifier of that row.                                                                 | string or number         |
| `onSelectionChange` | Fires when active row selection highlighting changes. Sends a single row object, or an array of objects if multi-selection is enabled.                     | object or array\<object> |
| `onRowClick`        | Fires when a user clicks anywhere inside a grid row body, sending that row's data object.                                                                  | object                   |
| `onLinkClick`       | Fires when a cell marked as clickable is selected. Sends the row values and appends an `__origin__` tracking property containing the clicked column field. | object                   |

#### Automatic configuration

Feed raw data to the widget without creating manual entries in your column settings, and it auto-configures column spaces. It scans the first 100 entries, identifies data layouts, infers appropriate data types (such as `text`, `number`, `dateTime`, or `media`), and populates the layout panel automatically.

<figure><img src="/files/A4LdzfREp5TxdkZ8IwnQ" alt=""><figcaption><p>Default view generated by dragging in random person data.</p></figcaption></figure>

## Configuration

Set the widget's defaults in the settings panel.

### Appearance

| **Property**            | **Label**             | **Description**                                                                                               | **Type** |
| ----------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------- | -------- |
| `pagingMode`            | Paging mode           | Lobs records continuously via infinite scrolling or structures them into a standard page navigation index.    | string   |
| `showBorders`           | Show borders          | Toggles the visibility of outer perimeter boundaries around the grid container.                               | boolean  |
| `showColumnHeaders`     | Show headers          | Toggles the visibility of text headers at the top of grid columns.                                            | boolean  |
| `showColumnLines`       | Show vertical lines   | Toggles thin border divider lines separating neighboring columns.                                             | boolean  |
| `showRowLines`          | Show horizontal lines | Toggles thin border divider lines separating consecutive rows.                                                | boolean  |
| `rowAlternationEnabled` | Alternate row color   | Toggles zebra-striping style background shifts on alternating table rows.                                     | boolean  |
| `columnAutoWidth`       | Column auto width     | Dynamically scales widths across columns to prevent text truncation based on row text volumes.                | boolean  |
| `detailMode`            | Detail mode           | Controls the display layout flow orientation inside expanded master-detail rows (`horizontal` or `vertical`). | string   |
| `labelMode`             | Label mode            | Selects structural label styling patterns for fields built inside form edit sheets.                           | string   |
| `fontSizeContent`       | Font size content     | Adjusts the typography point text size for cell contents across rows.                                         | integer  |
| `fontSizeLabel`         | Font size label       | Adjusts the typography point text size for header categories and field labels.                                | integer  |

### Data display

| **Property**            | **Label**                     | **Description**                                                                                       | **Type** |
| ----------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------- | -------- |
| `selectionMode`         | Selection mode                | Selects row activation capabilities (`single` selection, `multiple` selection checklists, or `none`). | string   |
| `allowColumnReordering` | Allow column reordering       | Lets users drag column category headers horizontally to swap position paths.                          | boolean  |
| `allowColumnResizing`   | Allow column resizing         | Lets users drag the outer borders of column headers to manually adjust widths.                        | boolean  |
| `allowColumnFixing`     | Allow column pinning          | Lets users pin selected columns to lock them in place during horizontal scrolling.                    | boolean  |
| `allowColumnChoosing`   | Allow column choosing         | Embeds a chooser action button letting users hide or reveal columns dynamically.                      | boolean  |
| `allowMultipleSorting`  | Allow multiple column sorting | Lets users group-sort columns against multiple data parameters sequentially.                          | boolean  |
| `allowGrouping`         | Allow grouping                | Activates a drag-and-drop header panel area to group rows by shared column fields.                    | boolean  |
| `allowSearching`        | Allow searching               | Embeds a global search box field inside the header to filter all matched strings.                     | boolean  |
| `allowRowFiltering`     | Allow row filtering           | Lays out interactive input field filters directly underneath column headers.                          | boolean  |
| `allowHeaderFiltering`  | Allow header filtering        | Embeds a dropdown selection filtering checklist directly into column headers.                         | boolean  |
| `allowFilterBuilding`   | Allow filter building         | Lets users compose multi-conditional advanced logical tree filters.                                   | boolean  |
| `showItemCount`         | Show item count               | Displays a summary count of the total visible record count inside the footer.                         | boolean  |

### Data editing

| **Property**          | **Label**               | **Description**                                                                                                     | **Type** |
| --------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------- | -------- |
| `mode`                | Mode                    | Chooses the interaction layout style when modifying cell values (`cell`, `row`, inline `form`, or a modal `popup`). | string   |
| `allowAdding`         | Allow adding            | Exposes creation shortcuts and empty field sheets to insert fresh records.                                          | boolean  |
| `allowUpdating`       | Allow updating          | Toggles entry modifiers letting users modify historical row items.                                                  | boolean  |
| `allowDeleting`       | Allow deleting          | Exposes row context tools to drop records out of the array dataset.                                                 | boolean  |
| `showAllFieldsOnEdit` | Show all fields on edit | Forces editing forms to display all data properties, bypassing normal row column exclusions.                        | boolean  |

### Data export

| **Property**              | **Label**                   | **Description**                                                                      | **Type** |
| ------------------------- | --------------------------- | ------------------------------------------------------------------------------------ | -------- |
| `allowPdfExport`          | Allow PDF export            | Exposes a toolbar option generating structured vector PDF sheets from grid datasets. | boolean  |
| `allowExcelExport`        | Allow Excel export          | Exposes a toolbar option compiling rows into native spreadsheet documents (.xlsx).   | boolean  |
| `allowCsvExport`          | Allow CSV export            | Exposes a toolbar option writing contents to flat comma-separated values files.      | boolean  |
| `allowExportSelectedData` | Allow export data selection | Restricts generated document prints exclusively to active highlighted rows.          | boolean  |
| `exportHint`              | Hint text                   | Customizes the prefix string prompt rendered inside file export toolbar buttons.     | string   |

### Data settings

Map object parameters from your database arrays into discrete grid columns.

| **Property** | **Label**     | **Description**                                                                                              | **Type** |
| ------------ | ------------- | ------------------------------------------------------------------------------------------------------------ | -------- |
| `dataField`  | Data field    | The raw object key mapping path extracted out of the row array dataset.                                      | string   |
| `caption`    | Column name   | The friendly header name string displayed at the top of the column row.                                      | string   |
| `visibility` | Visibility    | Controls layout visibility levels (`visible`, `hidden`, inside `detail` sheets, or completely `removed`).    | string   |
| `editing`    | Editing       | Enforces modification parameters for row edits (`optional`, `required` validation, `disabled`, or `hidden`). | string   |
| `widget`     | Editor widget | Dictates the interactive control interface loaded inside row modification sheets.                            | string   |

### Editor widget options

Configure input fields inside your editing panels based on your selected `widget` type.

| **Property**        | **Label**            | **Description**                                                                                         | **Type**         |
| ------------------- | -------------------- | ------------------------------------------------------------------------------------------------------- | ---------------- |
| `isClickable`       | Is clickable         | (`text` only) Renders values as selectable link text to run downstream actions.                         | boolean          |
| `min`               | Minimum              | (`number` and `slider` only) The lowest numeric value bound allowed for entry.                          | number           |
| `max`               | Maximum              | (`number` and `slider` only) The highest numeric value bound allowed for entry.                         | number           |
| `defaultValue`      | Default value        | (`number`, `slider`, `dropdown`, `tags` variants) The initial value used inside empty entries.          | string or number |
| `precision`         | Precision            | (`number` only) Caps the maximum count of fixed decimal fraction places shown.                          | number           |
| `currency`          | Currency             | (`number` only) Prepends currency identifier tags (such as `EUR` or `$`) ahead of values.               | string           |
| `handleLargeNumber` | Handle large numbers | (`number` only) Downsamples massive integers into condensed unit string variations (such as `1.2M`).    | boolean          |
| `options`           | Options              | (`dropdown`, `tags`, `slider`) A comma-separated selection configuration list mapping literal choices.  | string           |
| `switchedOnText`    | Switched on text     | (`switch` only) The active label text displayed when the toggle is toggled true.                        | string           |
| `switchedOffText`   | Switched off text    | (`switch` only) The inactive label text displayed when the toggle is toggled false.                     | boolean          |
| `dateType`          | Date type            | (`dateTime` only) Adjusts picker depths, choosing between `date`, `time`, or combining into `datetime`. | string           |
| `formatDescription` | Format description   | (`dateTime` only) Selects specific formatting options driven by preset properties or explicit tokens.   | string           |
| `mediaType`         | Media type           | (`media` only) Defines valid graphic and file asset formats (`png`, `jpeg`, `svg`, `pdf`).              | string           |
| `isCentralElement`  | Is central element   | (`media` only) Scales asset displays into massive core preview positions across forms.                  | boolean          |
| `thumbnailSize`     | Thumbnail size       | (`media` only) Defines the pixel height for preview imagery rendered inside row cells.                  | integer          |

## Video demo

{% embed url="<https://www.youtube.com/watch?v=m76VLWgqNaw>" %}

## Tips and tricks

### Performance with large datasets

* **Virtual scrolling**: The data grid scales efficiently with substantial datasets out of the box. When choosing `virtual` inside `pagingMode`, the widget streams and paints row nodes exclusively within the active screen viewport. This allows you to handle thousands of rows with fast layout responses.
* **Data parsing rules**: The widget replaces object periods (`.`) with hyphens (`-`) dynamically when processing deep JSON strings to avoid tracking breaks. When addressing deep object data structures, target your paths using clean hyphen boundaries.

### User experience and layout

* **Master-detail sections**: Expand row footprints smoothly by designating secondary column groups to `detail` visibility. When users toggle the row, hidden row fields load into sub-panels, creating clean dashboard layouts.
* **Column curation**: Keep interactions user-centric. Enable column choosing and column resizing options so developers or app users can adjust visual widths and hide columns to suit unique workspaces.


# Data list

The data list widget displays a collection of data objects inside a scrollable list layout. It renders each record as a mini-form template, letting you view and edit detailed records in a compact space.

<figure><img src="/files/sD7gFgpaSTbuU4tUJbRV" alt=""><figcaption></figcaption></figure>

## Data binding

### Function output or modifier to widget

| **Property**  | **Description**                                                                  | **Type** |
| ------------- | -------------------------------------------------------------------------------- | -------- |
| `data`        | The array of data objects to populate within the list items.                     | array    |
| `searchValue` | Programmatically sets the search filter string value to filter list contents.    | string   |
| `editable`    | Programmatically toggles whether the fields within the list items can be edited. | boolean  |

### Widget to function input

| **Property**        | **Description**                                                                                                                   | **Type**                 |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
| `onChange`          | Fires when a field within a list item changes, sending the complete updated data object for that item.                            | object                   |
| `onSelectionChange` | Fires when active item highlights change, sending the selected item object, or an array of objects if multi-selection is enabled. | object or array\<object> |
| `onItemClick`       | Fires when a user clicks a list item (only when displaying multiple records), sending the clicked item's data payload.            | object                   |
| `onDelete`          | Fires when an item is deleted from the list, sending the unique identifier of the removed item.                                   | string or number         |

#### Automatic configuration

Feed data to the widget without defining any parameters in your data fields settings, and it auto-configures itself. It inspects the first record, generates a field for each object property, infers data types (such as `text`, `number`, `dateTime`, or `media`), and populates the data fields panel for further customization.

## Configuration

Set the widget's defaults in the settings panel.

### Appearance

These settings control the typography, spacing, and label layouts inside the list templates.

| **Property**          | **Label**         | **Description**                                                                                        | **Type**          |
| --------------------- | ----------------- | ------------------------------------------------------------------------------------------------------ | ----------------- |
| `colCount`            | Column count      | Sets the number of columns used to arrange inputs within each item form. Use `0` for automatic layout. | integer or string |
| `labelLocation`       | Label location    | Controls where to display field labels relative to their input editors (`top`, `left`, `right`).       | string            |
| `labelMode`           | Label mode        | Selects label visualization styles (`static`, `floating`, `hidden`, `outside`).                        | string            |
| `showColonAfterLabel` | Show colon        | Appends a colon suffix after each visible field label when checked.                                    | boolean           |
| `fontSizeContent`     | Font size content | Adjusts the typography point text size for input content and editor fields.                            | integer           |
| `fontSizeLabel`       | Font size label   | Adjusts the typography point text size for field labels.                                               | integer           |
| `verticalSpacing`     | Vertical spacing  | Adjusts the vertical pixel spacing between nested input fields within an item template.                | integer           |

### Data handling

These settings control the interactive features and payload tracking rules for the list canvas.

| **Property**          | **Label**               | **Description**                                                                                             | **Type** |
| --------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------- | -------- |
| `selectionMode`       | Selection mode          | Selects list item activation capabilities (`single` selection, `multiple` selection checklists, or `none`). | string   |
| `allowSearching`      | Allow searching         | Embeds an integrated search box panel above the list to filter items based on visible data fields.          | boolean  |
| `allowUpdating`       | Allow updating          | Lets users modify input fields directly within individual list items inline.                                | boolean  |
| `allowDeleting`       | Allow deleting          | Exposes interactive removal tools to delete items out of the list layout.                                   | boolean  |
| `showAllFieldsOnEdit` | Show all fields on edit | Forces the updated data payload to contain all item properties instead of only modified fields.             | boolean  |

### Data fields

Map properties from your object array into form items inside the list row templates.

| **Property** | **Label**     | **Description**                                                                                                                                                                                  | **Type** |
| ------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- |
| `dataField`  | Data field    | The raw object key mapping path extracted out of the entry dataset.                                                                                                                              | string   |
| `label`      | Label         | The friendly label text displayed alongside the input field.                                                                                                                                     | string   |
| `colSpan`    | Column span   | The number of layout columns the field occupies within the item grid template.                                                                                                                   | integer  |
| `visible`    | Visible       | Toggles the layout visibility of this field inside the item template.                                                                                                                            | boolean  |
| `widget`     | Editor widget | Dictates the interactive control interface loaded inside the item form (such as `text`, `textarea`, `number`, `slider`, `dateTime`, `dropdown`, `tags`, `checkbox`, `switch`, `color`, `media`). | string   |

### Editor widget options

Configure sub-properties nested inside your fields based on your selected `widget` type.

| **Property**        | **Label**            | **Description**                                                                                             | **Type**         |
| ------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------- |
| `min`               | Minimum              | (`number` and `slider` only) The lowest numeric value bound allowed for entry.                              | number           |
| `max`               | Maximum              | (`number` and `slider` only) The highest numeric value bound allowed for entry.                             | number           |
| `defaultValue`      | Default value        | (`number`, `slider`, `dropdown`, `tags` variants) The initial value used inside empty entries.              | string or number |
| `precision`         | Precision            | (`number` only) Caps the maximum count of fixed decimal fraction places shown.                              | number           |
| `currency`          | Currency             | (`number` only) Prepends currency identifier tags (such as `EUR` or `$`) ahead of values.                   | string           |
| `handleLargeNumber` | Handle large numbers | (`number` only) Downsamples massive integers into condensed unit string variations (such as `1.2M`).        | boolean          |
| `discover`          | Discover options     | (`dropdown` and `tags` only) Automatically extracts unique choices directly from historical dataset values. | boolean          |
| `options`           | Options              | (`dropdown` and `tags` only) A comma-separated list mapping hardcoded selection options.                    | string           |
| `switchedOnText`    | Switched on text     | (`switch` only) The active label text displayed when the toggle is toggled true.                            | string           |
| `switchedOffText`   | Switched off text    | (`switch` only) The inactive label text displayed when the toggle is toggled false.                         | string           |
| `dateType`          | Date type            | (`dateTime` only) Adjusts picker depths, choosing between `date`, `time`, or combining into `datetime`.     | string           |
| `formatDescription` | Format description   | (`dateTime` only) Selects specific formatting options driven by preset properties or explicit tokens.       | string           |
| `isCentralElement`  | Is central element   | (`media` only) Scales asset displays into massive core preview positions across forms.                      | boolean          |
| `thumbnailSize`     | Thumbnail size       | (`media` only) Defines the pixel height for preview imagery rendered inside list fields.                    | integer          |


# Data tiles

The data tiles widget displays a collection of data objects inside a responsive, tiled grid layout. Each tile functions as a miniature form template, making it ideal for building visual galleries, summary matrices, or interactive status dashboards.

<figure><img src="/files/IsYkVxfdlUeutc8fFxkK" alt="" width="563"><figcaption><p>A Data Tiles widget displaying 6 objects with multiple data fields each</p></figcaption></figure>

## Data binding

### Function output or modifier to widget

| **Property** | **Description**                                                                     | **Type** |
| ------------ | ----------------------------------------------------------------------------------- | -------- |
| `data`       | An array of data objects, where each discrete object renders as an individual tile. | array    |
| `isLoading`  | Toggles a visual loading overlay indicator during background data operations.       | boolean  |

### Widget to function input

| **Property** | **Description**                                                                                                                                                                    | **Type** |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `onChange`   | Fires when a user modifies a field inside any tile. Triggers a baseline `onChange` event containing the complete row object, alongside a targeted legacy `onUpdate` event payload. | object   |

#### Automatic configuration

Feed raw data to the widget without pre-defining any structural entries in your data fields, and it auto-configures itself. It inspects the properties of the first available record, generates a field entry for each key path, infers matching editor data types (such as `text`, `number`, `dateTime`, or `media`), and loads them into your configuration panel for further design adjustment.

## Configuration

Set the widget's defaults in the settings panel.

### Tile settings

#### Appearance

These settings control the dimensions, alignment, and internal label tracking parameters of the individual tile blocks.

| **Property**          | **Label**         | **Description**                                                                                             | **Type**          |
| --------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------- | ----------------- |
| `justification`       | Justification     | Aligns row layouts within the parent grid container area (`flex-start`, `flex-end`, or `center`).           | string            |
| `tileWidth`           | Tile width        | Enforces a fixed horizontal structural width for every tile item in pixels.                                 | number            |
| `tileHeight`          | Tile height       | Enforces a fixed vertical structural height for every tile item in pixels.                                  | number            |
| `colCount`            | Column count      | Sets the number of layout columns used to arrange inputs inside each tile. Use `auto` for flexible scaling. | integer or string |
| `labelLocation`       | Label location    | Dictates where to anchor text labels relative to their input editors (`top`, `left`, `right`).              | string            |
| `labelMode`           | Label mode        | Selects structural label visualization styles (`static`, `floating`, `hidden`, `outside`).                  | string            |
| `showColonAfterLabel` | Show colon        | Appends a typographical colon suffix after each visible field label text when checked.                      | boolean           |
| `fontSizeContent`     | Font size content | Adjusts the typography point text size for input content and editor fields.                                 | integer           |
| `fontSizeLabel`       | Font size label   | Adjusts the typography point text size for field labels and tile text elements.                             | integer           |

#### Data handling

These properties manage the interactive features and payload compilation rules for tile modifications.

| **Property**          | **Label**               | **Description**                                                                                                      | **Type** |
| --------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------- | -------- |
| `allowUpdating`       | Allow updating          | Toggles form input controls out of read-only states, letting users modify parameters inline.                         | boolean  |
| `showAllFieldsOnEdit` | Show all fields on edit | Forces update event payloads to return the entire compiled item object instead of transmitting only modified fields. | boolean  |

### Data fields

Map text keys and array metrics extracted from your data source into visible tile fields.

| **Property** | **Label**   | **Description**                                                                                         | **Type** |
| ------------ | ----------- | ------------------------------------------------------------------------------------------------------- | -------- |
| `titleField` | Title field | Selects a specific object property path to display as a prominent, bold header at the top of each tile. | string   |
| `titleColor` | Title color | Overrides the global theme template text color for the primary tile title text element.                 | string   |
| `dataFields` | Data fields | An array of field mapping configurations detailing individual inputs nested inside each tile.           | array    |

#### Field properties

Each individual configuration object nested inside the `dataFields` configuration array supports these properties:

| **Property** | **Description**                                                                                | **Type** |
| ------------ | ---------------------------------------------------------------------------------------------- | -------- |
| `dataField`  | The raw object key mapping path extracted out of the item record object.                       | string   |
| `label`      | The friendly descriptive text displayed as the field category header label.                    | string   |
| `colSpan`    | The total number of layout columns this specific field occupies within the tile template grid. | integer  |
| `visible`    | Toggles the visual rendering visibility of this field item within the tile container.          | boolean  |
| `widget`     | Dictates the active user interface input control loaded inside the block template layout.      | string   |

### Editor widget options

Configure sub-properties nested inside your field structures based on your selected `widget` type.

| **Property**        | **Label**            | **Description**                                                                                                   | **Type**         |
| ------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------- | ---------------- |
| `min`               | Minimum              | (`number` and `slider` only) The lowest numeric value bound allowed for entry.                                    | number           |
| `max`               | Maximum              | (`number` and `slider` only) The highest numeric value bound allowed for entry.                                   | number           |
| `defaultValue`      | Default value        | (`number`, `slider`, `dropdown`, `tags` variants) The initial value used inside empty entries.                    | string or number |
| `precision`         | Precision            | (`number` only) Caps the maximum count of fixed decimal fraction places shown.                                    | number           |
| `currency`          | Currency             | (`number` only) Prepends currency identifier tags (such as `EUR` or `$`) ahead of values.                         | string           |
| `handleLargeNumber` | Handle large numbers | (`number` only) Downsamples massive integers into condensed unit string variations (such as `1.2M`).              | boolean          |
| `discover`          | Discover options     | (`dropdown` and `tags` only) Automatically extracts unique choices directly from historical dataset values.       | boolean          |
| `options`           | Options              | (`dropdown` and `tags` only) A comma-separated list mapping hardcoded selection options.                          | string           |
| `switchedOnText`    | Switched on text     | (`switch` only) The active label text displayed when the toggle is toggled true.                                  | string           |
| `switchedOffText`   | Switched off text    | (`switch` only) The inactive label text displayed when the toggle is toggled false.                               | string           |
| `dateType`          | Date type            | (`dateTime` only) Adjusts picker depths, choosing between `date`, `time`, or combining into `datetime`.           | string           |
| `formatDescription` | Format description   | (`dateTime` only) Selects specific formatting options driven by preset properties or explicit tokens.             | string           |
| `justification`     | Justification        | (`media` only) Aligns the asset element layout position within its template box area (`left`, `center`, `right`). | string           |
| `thumbnailSize`     | Thumbnail size       | (`media` only) Defines the pixel height dimension for preview imagery loaded inside tile views.                   | integer          |

## Video demo

{% embed url="<https://youtu.be/p9-NG_BB6hU>" %}
Data tiles explained
{% endembed %}




---

[Next Page](/llms-full.txt/1)

