Node.js / TypeScript · recipe
Subscribe to data changes in Node.js
Create a subscription with the publishing interval your consumer needs, then monitor items with their own sampling interval, queue size and filter. node-opcua exposes every parameter that matters, including the deadband most wrappers hide.
| Stack | node-opcua |
|---|---|
| Version | 2.181.1 |
The code
const {
OPCUAClient, AttributeIds, TimestampsToReturn,
DataChangeFilter, DataChangeTrigger, DeadbandType,
} = require("node-opcua");
(async () => {
const client = OPCUAClient.create({ endpointMustExist: false });
await client.connect("opc.tcp://opcua.umati.app:4840");
const session = await client.createSession();
const subscription = await session.createSubscription2({
requestedPublishingInterval: 1000, // what the consumer needs
requestedLifetimeCount: 100,
requestedMaxKeepAliveCount: 10,
maxNotificationsPerPublish: 100,
publishingEnabled: true,
priority: 10,
});
subscription.on("keepalive", () => console.log("keepalive"));
subscription.on("terminated", () => console.log("subscription terminated"));
const item = await subscription.monitor(
{ nodeId: "i=2258", attributeId: AttributeIds.Value },
{
samplingInterval: 250,
queueSize: 10,
discardOldest: true,
filter: new DataChangeFilter({
trigger: DataChangeTrigger.StatusValue,
deadbandType: DeadbandType.Absolute,
deadbandValue: 0.5,
}),
},
TimestampsToReturn.Both
);
item.on("changed", (dv) => {
console.log(dv.value.value, dv.statusCode.toString(), dv.sourceTimestamp);
});
setTimeout(async () => {
await subscription.terminate();
await session.close();
await client.disconnect();
}, 5000);
})();
What it prints
2026-09-08T03:45:00.102Z Good (0x00000000) 2026-09-08T03:45:00.102Z
2026-09-08T03:45:01.104Z Good (0x00000000) 2026-09-08T03:45:01.104Z
keepalive
Notes
- requestedPublishingInterval is the delivery rate; samplingInterval is how often the server looks. Set the first from what the consumer needs, not from the fastest the server can manage.
- The server may revise your parameters. Read subscription.publishingInterval after creation to see what you actually got.
- Percent deadband requires EURange on the node. Absolute is the safe default.
- Listen for `terminated`. A subscription deleted server-side is a silent data stop otherwise.
- Keep the number of distinct publishing intervals small: each one is another subscription on the server.
What breaks first
Data arrives but with gaps, and every status code is Good
The queue overflowed between publishes. Raise queueSize, slow the sampling interval, or add a deadband so fewer notifications are generated.
GoodOverloadThe queue overflowed between publishes. Raise queueSize, slow the sampling interval, or add a deadband so fewer notifications are generated.
Other recipes in this stack
Concepts on this page
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.