Why Send Custom ONVIF Events?
The Send Custom Event Notification feature lets you inject an arbitrary ONVIF-compliant event into the server's notification pipeline. Once submitted, the event is immediately dispatched to all active subscribers — both push-mode (HTTP Notify) and poll-mode (PullMessages) consumers.
This capability is useful for:
- Event-Driven Integration Testing: Validate that your VMS or ONVIF client correctly reacts to events (motion, relay triggers, tamper, custom analytics) without waiting for a real hardware event.
- Subscriber Behavior Validation: Confirm that push-mode and poll-mode subscribers both receive events with the correct topic, source, and data payloads.
- Simulating Device Triggers: Emulate relay outputs, digital inputs, or any custom event type — even those not natively generated by the device — to exercise your application's event handling logic.
- Repeatable Test Scenarios: Trigger the exact same event payload repeatedly to reproduce and debug integration issues deterministically.
Prerequisites: Active Subscribers
A subscriber must be connected before events can be delivered. Events are dispatched to all currently active subscriptions:
- Push-mode subscribers (
Subscribe): Must have an active subscription with a reachableConsumerReferenceendpoint. The server sends anHTTP POST Notifyto each subscriber's endpoint. - Poll-mode subscribers (
CreatePullPointSubscription): Must have an active subscription and be polling viaPullMessages. Events are queued and delivered in the next poll response.
Step 1: Access the Custom Event Page
Open a browser and navigate to the server's web interface:
http://<server-ip>:<http-port>/main.html
Replace <server-ip> with the ONVIF Server's IP address and <http-port> with the port configured in <http_port>.
Tip: After updating main.html or the server binary, force-refresh the browser with Ctrl+F5 to bypass cached content.
Step 2: Understand the Page Layout
The custom event page contains the following elements:
| Element | Purpose |
|---|---|
| Textarea | Paste your ONVIF event XML body here. |
| Send Event button (blue) | Submits the XML to /SendEvent. |
| Clear button (gray) | Resets the form. |
| Result bar (green/red) | Shows success or error feedback after submission. |
| Example block | Copy-paste reference XML for quick testing. |
Step 3: Understand the Event XML Format
The server expects a single <wsnt:NotificationMessage> element containing a Topic and a Message.
Complete Example
<wsnt:NotificationMessage>
<wsnt:Topic Dialect="http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet">
tns1:Device/Trigger/Relay
</wsnt:Topic>
<wsnt:Message>
<tt:Message UtcTime="2026-08-06T07:31:07Z" PropertyOperation="Initialized">
<tt:Source>
<tt:SimpleItem Name="RelayToken" Value="RelayOutputToken_1"/>
</tt:Source>
<tt:Data>
<tt:SimpleItem Name="LogicalState" Value="active"/>
</tt:Data>
</tt:Message>
</wsnt:Message>
</wsnt:NotificationMessage>
Field Reference
| Field | Required | Description |
|---|---|---|
wsnt:NotificationMessage |
Yes | Root element. Must appear exactly once. |
wsnt:Topic |
Yes | The event topic string (e.g., tns1:Device/Trigger/Relay). |
wsnt:Topic/@Dialect |
No | Topic expression dialect URI. Defaults to http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet. |
wsnt:Message |
Yes | Wrapper for the event payload. |
tt:Message |
Yes | The actual message body. |
tt:Message/@UtcTime |
No | ISO 8601 UTC timestamp. Defaults to the server's current time if omitted. |
tt:Message/@PropertyOperation |
No | One of: Initialized, Deleted, Changed. Defaults to Changed. |
tt:Source |
No | Source descriptors as a <tt:SimpleItem> list. |
tt:Data |
No | Payload data as a <tt:SimpleItem> list. |
tt:SimpleItem |
No | A name-value pair with Name and Value attributes. |
Step 4: Send a Custom Event
- Open the page (
http://<server-ip>:<http-port>/main.html) in a browser. - Paste your event XML into the textarea (or type it directly).
- Click "Send Event" (the blue button). The XML is submitted to the
/SendEventendpoint. - Observe the result:
- A green bar indicates success, with the topic echoed back.
- A red bar indicates failure, with the reason displayed.
- Optionally click "Clear" to reset the form and submit another event.
Once the event is accepted, it is immediately dispatched to all active subscribers: push-mode subscribers receive an HTTP POST Notify, and poll-mode subscribers receive the event in their next PullMessages response.
Response Messages
All responses use HTTP 200 with a JSON body. Parse the result field to distinguish success from failure.
| Scenario | HTTP Status | JSON Response |
|---|---|---|
| Success | 200 | {"result":"ok","topic":"tns1:Device/Trigger/Relay"} |
| Empty body | 200 | {"result":"err","reason":"empty body"} |
| XML parse error | 200 | {"result":"err","reason":"xml parse failed"} |
| Missing Topic | 200 | {"result":"err","reason":"topic is required"} |
| Out of memory | 200 | {"result":"err","reason":"out of memory"} |
| Network failure | — | Browser displays "Network error" |
Example: Simulate a Digital Input Change
Below is another ready-to-use event payload that simulates a digital input state change. Paste it into the textarea and click Send Event.
<wsnt:NotificationMessage>
<wsnt:Topic Dialect="http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet">
tns1:Device/Trigger/DigitalInput
</wsnt:Topic>
<wsnt:Message>
<tt:Message PropertyOperation="Changed">
<tt:Source>
<tt:SimpleItem Name="DigitalInputToken" Value="DigitalInput_1"/>
</tt:Source>
<tt:Data>
<tt:SimpleItem Name="LogicalState" Value="true"/>
</tt:Data>
</tt:Message>
</wsnt:Message>
</wsnt:NotificationMessage>
Troubleshooting
| Symptom | Likely Cause | Solution |
|---|---|---|
| Button not visible | Browser cache | Force-refresh with Ctrl+F5. |
| "Network error" | Server not running or wrong port | Verify the <http_port> in the configuration and that the server is running. |
| "xml parse failed" | Malformed XML | Validate the XML with an XML formatter before submitting. |
| "topic is required" | Missing <wsnt:Topic> element |
Add a <wsnt:Topic> element with a valid topic string. |
| Subscribers not receiving | No active subscription, or filter mismatch | Verify subscriptions are active; check the TopicExpression filter in the Subscribe request. |
| Subscribers receive empty events | Source/Data missing | Add <tt:Source> and/or <tt:Data> sections to the event payload. |
Best Practices
- Ensure Subscribers Are Connected First: Events are dispatched to currently active subscriptions only. Subscribe (push-mode) or create a pull-point (poll-mode) before sending a custom event to avoid silently missing deliveries.
- Match the Topic Filter: If a subscriber is not receiving your custom event, verify that the event's
Topicmatches the subscriber'sTopicExpressionfilter. A topic outside the filter is dropped by the server. - Always Include Source and Data: Even though
<tt:Source>and<tt:Data>are optional, always include them for realistic event payloads. Subscribers commonly parse source tokens (e.g.,RelayToken) and data properties (e.g.,LogicalState) to decide how to react. - Use Explicit PropertyOperation Values: Use
Initializedfor the first occurrence of a state,Changedfor subsequent transitions, andDeletedwhen a state no longer applies. This mirrors real ONVIF device behavior. - Test Both Push and Poll Modes: Validate that your event reaches both an HTTP Notify push subscriber and a PullMessages poll subscriber. Some client implementations handle only one mode, and testing both catches integration gaps.
- Force-Refresh After Updates: Whenever
main.htmlor the server binary changes, useCtrl+F5in the browser to bypass cached content and ensure you are testing the latest build.