For the complete documentation index, see llms.txt. This page is also available as Markdown.

OPC UA Server

Expose device data as OPC UA tags that PLCs, SCADA systems, and other industrial clients can read and write.

OPC UA (Open Platform Communications Unified Architecture) is an industrial communication protocol for exchanging data between devices, PLCs, and SCADA systems. The OPC UA Server is an edge container service that publishes tags on the device so industrial clients can read inference results and write values back.

You define the tags, folders, and server settings from the Deployment Manager Configuration tab, then point your OPC UA client at the device.

OPC UA Server is available exclusively for Enterprise customers. Contact the Roboflow sales team to learn more.

Connection Details

Replace <device-ip> with the IP address shown on the device page in Deployment Manager.

Purpose
Address

OPC UA endpoint

opc.tcp://<device-ip>:4840/opcua/server

Web UI and REST API

http://<device-ip>:8092

Port
Protocol
Purpose

4840

OPC UA Binary

Industrial client connections (PLCs, SCADA)

8092

HTTP

Web UI, REST API, documentation

Configuration Source

The "Configuration Source" toggle at the top of the Configure modal controls where the tag and folder configuration comes from. Only one source is ever active on the device at a time.

Source
Stored in
Use it when

"Web UI"

OPCUA_CONFIG

You want to define tags, folders, and server settings inline in the modal. This is the default.

"File"

OPCUA_CONFIG_FILE

The configuration is too large for an environment variable, such as a deployment with thousands of tags. Point the server at a path on the device (ex: /data/opcua-config.json).

In "File" mode the server validates at startup that the file exists, is readable, and is not empty, and fails to start with an explicit log entry if any of that is untrue. OPCUA_CONFIG_FILE takes precedence over OPCUA_CONFIG.

Switching sources keeps both the inline values and the file path while the modal is open. On save, the source you did not pick is cleared, so exactly one of the two variables is set. In "File" mode the service card shows the configured file path in place of the inline tag list.

Server Settings

Setting
Description

"Server Name"

Human-readable name for the server instance, shown to clients browsing the network.

"Namespace URI"

Unique URI identifying the server namespace that tags are registered under. Defaults to http://opcua.roboflow.run.

"Max Sessions"

How many OPC UA clients may be connected at once. Defaults to 200.

Every client holds one session, including each inference pod writing tags and each SCADA connection. A session belonging to a client that crashed is only released when the server times it out, so a busy site can hold more sessions than it has live clients. Once the cap is reached, further clients are refused with BadTooManySessions and their tags stop updating. Raise the value if a site runs more concurrent clients than the default. Setting it in the modal writes it into the server config, and OPCUA_MAX_SESSIONS can override it per device for hand-managed deployments.

Folders and Tags

Folders organize tags into a hierarchy. Each folder has a name and an optional description, and appears as a node in the OPC UA address space so clients can browse and discover tags. A tag can belong to a folder or sit at the root level.

Tags define the data points the server exposes. Each tag has these fields:

Field
Description

"Display Name"

Human-readable name shown to OPC UA clients.

"Browse Name"

Programmatic identifier used in the address space. Generated from the display name.

"Data Type"

The type of value the tag holds.

"Access Level"

Whether the tag is ReadWrite or ReadOnly.

"Folder"

Which folder the tag belongs to, or Root if unassigned.

"Initial Value"

Starting value when the server starts. Validated against the data type.

"Description"

Optional label describing what the tag is for.

Data Types

Type
Description
Example

Boolean

True or false

true

Int32

32-bit signed integer

42

Float

32-bit floating point

3.14

Double

64-bit floating point

3.14159265359

String

UTF-8 text

Running

DateTime

ISO 8601 timestamp

2024-01-15T10:30:00Z

These are the types the Configure modal offers. A hand-written configuration file may also use Int16, UInt16, and UInt32, which the server accepts.

Access Levels

ReadWrite tags can be read and written by OPC UA clients as well as the REST API, CLI, and web UI. Use them for control outputs, setpoints, and user-adjustable values.

ReadOnly tags reject OPC UA client writes with BadNotWritable. The REST API, CLI, and web UI can still update the value regardless of access level, so use ReadOnly for sensor values, calculated outputs, and system status that only the device should produce.

Optional Constraints

Numeric types support "Min Value" and "Max Value" to restrict the allowed range, plus "Engineering Units" for a descriptive unit label (ex: °C, PSI, RPM). String types support "Max Length" to cap the character count.

Authentication

The server allows anonymous connections by default, using SecurityPolicy None. Turn on "Require authentication" in the Configure modal to require a username and password from every client.

When the toggle is on you must supply both a username and a password. The password is hashed with bcrypt before it is stored, so the original is never saved and cannot be retrieved later. To change the password on an existing server, enter a new one in the Configure modal, or leave the field blank to keep the current password. Turning the toggle off restores anonymous access.

The credentials are stored as two environment variables, which must be set together or both left unset:

Variable
Description

OPCUA_USERNAME

Plain-text username for client authentication.

OPCUA_PASSWORD_HASH

Bcrypt hash of the password at salt rounds 10, starting with $2b$10$.

Tag Reporting

The server can report its tags to Roboflow on a schedule, so you can see what it serves without a site visit. Set this in the "Tag Reporting" section of the Configure modal.

Setting
Description

"Send periodic tag reports"

Turns reporting on or off. On by default.

"Include tag values"

Sends the current value of each tag. Turn it off to send tag counts only. On by default.

"Reporting Interval"

Seconds between reports. Defaults to 60.

The settings are stored as environment variables, which the server reads at startup:

Variable
Default
Description

OPCUA_SNAPSHOT_INTERVAL_SECONDS

60

Seconds between reports. 0 turns reporting off.

OPCUA_SNAPSHOT_INCLUDE_VALUES

true

false sends tag counts only.

OPCUA_SNAPSHOT_TTL_SECONDS

derived

How long a report stays current. The modal derives this from the interval and rewrites it every time you save.

A value the server does not accept turns reporting off rather than falling back to the default, so a typo stops reports. The device page shows such a device as not reporting.

If any of these variables is set by reference ({$ref}), the modal cannot edit reporting and leaves it as it is on save. Replace the reference with a literal value to manage reporting from the form.

Monitoring

The device page shows a live OPC UA status card with the connected client count, sessions in use against "Max Sessions", and the latest tag report. A device on an image older than tag reporting says so in place of the report.

When the server hits the session cap and refuses new clients, the card shows a banner with the session count, the cap, and how many clients were refused. To get an email about it, add an "OPC UA Refusing Clients" alert from the device's "Device Alerts" tab and set how many minutes of refusals to allow first. See Set up Device Alerts.

Web Interface

The server hosts a web interface at http://<device-ip>:8092.

Page
Path
Contents

Dashboard

/

All configured tags with current values, refreshed every 2 seconds. Any tag's value can be edited through an edit dialog, regardless of access level.

Documentation

/docs.html

Server guide, configuration format reference, and troubleshooting notes.

API Explorer

/api/docs

Interactive Swagger UI for testing endpoints and viewing request and response schemas.

HTTP API

The REST API gives programmatic access to tag values and server information. All endpoints return JSON. The base URL is http://<device-ip>:8092/api. See Services for the rules shared by all on-device service APIs.

Tag structure is immutable at runtime. Tags and folders come from the OPCUA_CONFIG environment variable, or the file named by OPCUA_CONFIG_FILE for large configurations, and cannot be created, changed, or deleted through this API. Only values can be written.

Read and Write Tag Values

accessLevel governs the OPC UA protocol, not this API. A tag marked ReadOnly rejects writes from OPC UA clients with BadNotWritable but remains writable here, which is how a pipeline publishes a sensor value that industrial clients should only consume.

List all tags

get

Returns all configured tags with their current values.

Responses
200

List of tags with current values

application/json
get/tags
GET /api/tags HTTP/1.1
Host: device-ip:8092
Accept: */*
200

List of tags with current values

{
  "tags": [
    {
      "id": "text",
      "nodeId": "text",
      "displayName": "text",
      "dataType": "Boolean",
      "accessLevel": "ReadOnly",
      "currentValue": true,
      "lastUpdated": "2026-01-01T00:00:00.000Z",
      "folder": "text"
    }
  ]
}

Get a single tag

get

Returns a single tag with its current value.

Path parameters
idstringRequired

Tag ID

Responses
200

Tag with current value

application/json
get/tags/{id}
GET /api/tags/{id} HTTP/1.1
Host: device-ip:8092
Accept: */*
{
  "tag": {
    "id": "text",
    "nodeId": "text",
    "displayName": "text",
    "dataType": "Boolean",
    "accessLevel": "ReadOnly",
    "currentValue": true,
    "lastUpdated": "2026-01-01T00:00:00.000Z",
    "folder": "text"
  }
}

Update tag value

put

Updates the value of a tag. Tags with accessLevel: "ReadOnly" reject writes over the OPC UA protocol but remain writable through this endpoint.

Path parameters
idstringRequired

Tag ID

Body
valueone ofRequired

New value to set

booleanOptional
or
numberOptional
or
stringOptional
Responses
200

Updated tag with new value

application/json
put/tags/{id}/value
PUT /api/tags/{id}/value HTTP/1.1
Host: device-ip:8092
Content-Type: application/json
Accept: */*
Content-Length: 14

{
  "value": true
}
{
  "tag": {
    "id": "text",
    "nodeId": "text",
    "displayName": "text",
    "dataType": "Boolean",
    "accessLevel": "ReadOnly",
    "currentValue": true,
    "lastUpdated": "2026-01-01T00:00:00.000Z",
    "folder": "text"
  }
}

A write is rejected with 400 when the value is missing, the type does not match the tag's dataType, or it falls outside a configured minValue, maxValue, or maxLength. Writing to a tag that does not exist also returns 400, not 404. GET /tags/{id} does return 404, so use it if you need to distinguish an unknown tag from a bad value.

Configuration Endpoints

Read-only views of the running configuration, useful for discovering tag IDs and their constraints before writing.

Get full configuration

get

Returns the complete server configuration, including server settings, folders, and tag definitions. Read-only.

Responses
200

Full configuration

application/json
versionintegerRequired

Configuration version

get/config
GET /api/config HTTP/1.1
Host: device-ip:8092
Accept: */*
200

Full configuration

{
  "version": 1,
  "server": {
    "port": 1,
    "namespace": "text",
    "serverName": "text",
    "maxSessions": 1
  },
  "folders": [
    {
      "id": "text",
      "name": "text",
      "description": "text"
    }
  ],
  "tags": [
    {
      "id": "text",
      "nodeId": "text",
      "browseName": "text",
      "displayName": "text",
      "description": "text",
      "dataType": "Boolean",
      "folderId": "text",
      "accessLevel": "ReadOnly",
      "initialValue": true,
      "engineeringUnits": "text",
      "minValue": 1,
      "maxValue": 1,
      "maxLength": 1
    }
  ]
}

Get all folders

get

Returns all folder definitions.

Responses
200

List of folders

application/json
get/config/folders
GET /api/config/folders HTTP/1.1
Host: device-ip:8092
Accept: */*
200

List of folders

{
  "folders": [
    {
      "id": "text",
      "name": "text",
      "description": "text"
    }
  ]
}

Sessions and Health

Once maxSessions is reached, further clients are refused with BadTooManySessions, so compare sessionCount against maxSessions for headroom.

A 200 from /subscriptions with a zeroed session list and maxSessions omitted means the OPC UA server is not running. Treat it as an outage rather than a warm-up: if the endpoint answers at all, startup has already finished or failed. Confirm with /health, which reports status: "unhealthy" and opcuaServer: "stopped".

maxSessions is omitted rather than zeroed in that case so a consumer computing maxSessions - sessionCount does not read an unknown cap as a full one.

List active sessions and subscriptions

get

Returns the connected OPC UA clients and the tags each one is monitoring. Compare sessionCount against maxSessions for headroom before clients start being refused with BadTooManySessions.

A 200 with a zeroed session list and maxSessions omitted means the OPC UA server is not running. Treat it as an outage rather than a warm-up and confirm with /health. maxSessions is omitted rather than zeroed so a consumer computing maxSessions - sessionCount does not read an unknown cap as a full one.

Responses
200

Sessions and their subscriptions

application/json
sessionCountintegerRequired

Number of active sessions

maxSessionsintegerOptional

Configured maximum concurrent sessions, for headroom against sessionCount. Omitted when the OPC UA server is not running.

subscriptionCountintegerRequired

Total number of subscriptions across all sessions

get/subscriptions
GET /api/subscriptions HTTP/1.1
Host: device-ip:8092
Accept: */*
200

Sessions and their subscriptions

{
  "sessionCount": 1,
  "maxSessions": 1,
  "subscriptionCount": 1,
  "sessions": [
    {
      "sessionId": "text",
      "sessionName": "text",
      "clientDescription": "text",
      "connectedAt": "2026-01-01T00:00:00.000Z",
      "lastContactTime": "2026-01-01T00:00:00.000Z",
      "subscriptionCount": 1,
      "subscriptions": [
        {
          "subscriptionId": 1,
          "publishingInterval": 1,
          "monitoredItemCount": 1,
          "monitoredItems": [
            {
              "nodeId": "text",
              "displayName": "text",
              "samplingInterval": 1
            }
          ]
        }
      ]
    }
  ]
}

/subscriptions is missing from the spec the device serves at /api/openapi.json. The route is live regardless, and it is documented here.

/health returns 200 whether or not the OPC UA server is running. Check status and opcuaServer rather than the status code.

Health check

get

Returns the health status of the OPC UA server and API.

Responses
200

Health status. Returns 200 even when the OPC UA server is stopped, with status set to unhealthy.

application/json
statusstring · enumRequired

Overall server health status

Possible values:
opcuaServerstring · enumRequired

OPC UA server status

Possible values:
uptimeintegerRequired

Server uptime in seconds

tagCountintegerRequired

Number of configured tags

errorstringOptional

Why the OPC UA server is not running. Present only when opcuaServer is "stopped".

get/health
GET /api/health HTTP/1.1
Host: device-ip:8092
Accept: */*
200

Health status. Returns 200 even when the OPC UA server is stopped, with status set to unhealthy.

{
  "status": "healthy",
  "opcuaServer": "running",
  "uptime": 3600,
  "tagCount": 5
}

CLI

The opcua-cli tool gives terminal access to the server for debugging, scripting, and quick tag operations when the web UI is not reachable.

Command
Description

list, ls

List all tags with current values

read <tag>

Read a specific tag value

write <tag> <value>

Write a value to a tag

status

Show server health and uptime

clients

List connected OPC UA clients

clients --detailed

List clients with subscription details

export

Export the configuration as JSON

Logging

Set LOG_LEVEL on the service to control verbosity. See Update Device Configuration for where to edit service environment variables, and View Device Logs for reading the output.

Level
Description

DEBUG

Detailed diagnostic information

INFO

General operational messages (default)

WARN

Potential issues that do not stop operation

ERROR

Errors that affect functionality

Values are case-insensitive, and an unrecognized value falls back to INFO.

Last updated

Was this helpful?