How to Send Custom ONVIF Events with ONVIF Server

A practical guide to injecting arbitrary ONVIF-compliant events into the Happytime ONVIF Server notification pipeline. Deliver events to all active push-mode and poll-mode subscribers for testing event-driven integrations, validating subscriber behavior, and simulating device triggers without physical hardware.

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 reachable ConsumerReference endpoint. The server sends an HTTP POST Notify to each subscriber's endpoint.
  • Poll-mode subscribers (CreatePullPointSubscription): Must have an active subscription and be polling via PullMessages. 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:

Custom Event Page URL
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

Custom Event XML — Relay Trigger
<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

  1. Open the page (http://<server-ip>:<http-port>/main.html) in a browser.
  2. Paste your event XML into the textarea (or type it directly).
  3. Click "Send Event" (the blue button). The XML is submitted to the /SendEvent endpoint.
  4. Observe the result:
    • A green bar indicates success, with the topic echoed back.
    • A red bar indicates failure, with the reason displayed.
  5. 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.

Custom Event XML — Digital Input
<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 Topic matches the subscriber's TopicExpression filter. 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 Initialized for the first occurrence of a state, Changed for subsequent transitions, and Deleted when 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.html or the server binary changes, use Ctrl+F5 in the browser to bypass cached content and ensure you are testing the latest build.