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.
Connection Details
Replace <device-ip> with the IP address shown on the device page in Deployment Manager.
OPC UA endpoint
opc.tcp://<device-ip>:4840/opcua/server
Web UI and REST API
http://<device-ip>:8092
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.
"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
"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:
"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
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:
OPCUA_USERNAME
Plain-text username for client authentication.
OPCUA_PASSWORD_HASH
Bcrypt hash of the password at salt rounds 10, starting with $2b$10$.
Set credentials through the Configure modal rather than by editing the environment variables. The modal generates the bcrypt hash for you, and setting OPCUA_PASSWORD_HASH by hand requires producing a valid hash externally.
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.
"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:
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.
"Include tag values" governs the periodic report only. The server still writes tag value changes to its container log, which Roboflow collects separately.
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.
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.
The HTTP API is unauthenticated. OPCUA_USERNAME and OPCUA_PASSWORD_HASH protect the OPC UA binary endpoint on port 4840, not port 8092. Anything that can reach port 8092 can write any tag.
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.
Returns all configured tags with their current values.
List of tags with current values
GET /api/tags HTTP/1.1
Host: device-ip:8092
Accept: */*
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"
}
]
}Returns a single tag with its current value.
Tag ID
Tag with current value
Tag not found
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"
}
}Updates the value of a tag. Tags with accessLevel: "ReadOnly" reject writes over the OPC UA protocol but remain writable through this endpoint.
Tag ID
New value to set
Updated tag with new value
Missing value, unknown tag, type mismatch, or constraint violation. Note that an unknown tag returns 400 here, not 404. Use GET /tags/{id}, which returns 404, to tell an unknown tag from a bad 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.
Returns the complete server configuration, including server settings, folders, and tag definitions. Read-only.
Full configuration
Configuration version
GET /api/config HTTP/1.1
Host: device-ip:8092
Accept: */*
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
}
]
}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.
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.
Sessions and their subscriptions
Number of active sessions
Configured maximum concurrent sessions, for headroom against sessionCount. Omitted when the OPC UA server is not running.
Total number of subscriptions across all sessions
GET /api/subscriptions HTTP/1.1
Host: device-ip:8092
Accept: */*
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
}
]
}
]
}
]
}/health returns 200 whether or not the OPC UA server is running. Check status and opcuaServer rather than the status code.
Returns the health status of the OPC UA server and API.
Health status. Returns 200 even when the OPC UA server is stopped, with status set to unhealthy.
Overall server health status
OPC UA server status
Server uptime in seconds
Number of configured tags
Why the OPC UA server is not running. Present only when opcuaServer is "stopped".
GET /api/health HTTP/1.1
Host: device-ip:8092
Accept: */*
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.
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.
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?