C · recipe

Browse an OPC UA address space in C

Build a UA_BrowseRequest with a filtered UA_BrowseDescription and walk the results. Filtering in the request matters more in C than anywhere else, because every reference you fetch is memory you have to manage.

Stackopen62541
Version1.5.8

The code

#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <stdio.h>

int main(void) {
    UA_Client *client = UA_Client_new();
    UA_ClientConfig_setDefault(UA_Client_getConfig(client));
    if (UA_Client_connect(client, "opc.tcp://opcua.umati.app:4840") != UA_STATUSCODE_GOOD) {
        UA_Client_delete(client); return 1;
    }

    UA_BrowseRequest req;
    UA_BrowseRequest_init(&req);
    req.requestedMaxReferencesPerNode = 100;
    req.nodesToBrowse = UA_BrowseDescription_new();
    req.nodesToBrowseSize = 1;
    req.nodesToBrowse[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
    req.nodesToBrowse[0].browseDirection = UA_BROWSEDIRECTION_FORWARD;
    req.nodesToBrowse[0].referenceTypeId =
        UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
    req.nodesToBrowse[0].includeSubtypes = true;
    req.nodesToBrowse[0].nodeClassMask =
        UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE;
    req.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL;

    UA_BrowseResponse res = UA_Client_Service_browse(client, req);

    for (size_t i = 0; i < res.resultsSize; i++)
        for (size_t j = 0; j < res.results[i].referencesSize; j++) {
            UA_ReferenceDescription *r = &res.results[i].references[j];
            printf("%d:%.*s  nodeclass=%d\n",
                   r->browseName.namespaceIndex,
                   (int)r->browseName.name.length, r->browseName.name.data,
                   r->nodeClass);
        }

    UA_BrowseRequest_clear(&req);
    UA_BrowseResponse_clear(&res);
    UA_Client_disconnect(client);
    UA_Client_delete(client);
    return 0;
}

What it prints

0:Server  nodeclass=1
3:Machines  nodeclass=1
2:DeviceSet  nodeclass=1

Notes

  • Clear both the request and the response. UA_BrowseResponse_clear frees the whole reference array, and forgetting it in a loop leaks steadily until the process dies.
  • requestedMaxReferencesPerNode plus continuation points is how you page a large address space. Do not ask for everything on a constrained device.
  • The nodeClassMask and referenceTypeId filters cut both network traffic and the memory you have to own.
  • For interactive exploration use a GUI or opcua-commander. Writing a browser in C to look around once is not a good use of anyone's afternoon.

What breaks first

A long-running browse loop grows the process's memory until it is killed BadOutOfMemory
Every UA_*Response must be cleared. Run the loop under Valgrind or ASan once: open62541's own CI does exactly that.

Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.

Free download
OPC UA Troubleshooting & Integration Checklist
The field-tested checklist engineers use to diagnose certificates, ports and namespace problems fast, plus a Python (asyncua) client template.
Get the free checklist →
Free, no course, no login