When you work with IP cameras long enough, you eventually hit the same frustrating moment: the camera is clearly doing something interesting, but the event stream you need is either noisy, hard to inspect, or completely invisible in the tools you have on hand.
That was the motivation behind this small project: a simple ONVIF Event Viewer written in pure Python, with no third-party dependencies, built to make live camera events easier to troubleshoot.
Source code: jsammarco/ONVIF-Event-Viewer

Why I Built It
In real deployments, ONVIF event troubleshooting is rarely just about confirming that a camera is online. The harder questions usually look more like this:
- Is the device actually publishing the event I care about?
- Is the event standard ONVIF, vendor-specific, or both?
- Is my client missing stateful events because of subscription behavior?
- Is the event there, but buried under a wall of less useful telemetry?
Those questions came up while testing Axis cameras and analytics events, including application-driven events that do not always show up the way people expect.
I wanted something that was:
- quick to run
- easy to read
- easy to modify
- dependency-free
- transparent enough to show exactly what the camera is returning
So instead of reaching for a full SDK or a large framework, I built a direct SOAP-based ONVIF event viewer using only the Python standard library.
What The Tool Does
The viewer connects directly to an ONVIF device, discovers the event service, creates a pull-point subscription, and starts polling for live events.
The interface is intentionally straightforward:
- a top panel for camera connection settings
- a filter bar for narrowing noisy event streams
- a list view of incoming events
- a bottom detail panel with formatted raw XML
That last part matters more than it sounds. When you are debugging analytics behavior, seeing prettified XML instead of a single compressed blob makes a big difference.
Why Raw XML Still Matters
A lot of integrations fail in the gap between “an event exists” and “the client interpreted it correctly.”
For example:
- timestamps may be stored as attributes instead of element text
- vendor-specific topics may appear under a different namespace
- stateful events may require a synchronization point after subscription
- the message body may contain the useful signal while the summary text looks incomplete
Having raw XML visible in the UI makes it much easier to answer questions like:
- What topic did the camera actually send?
- Did the payload include
UtcTime? - Is this a standard
tns1topic or an Axis-specifictnsaxistopic? - Did the camera return a property-style event that needs different handling?
That visibility is especially valuable when working with analytics applications such as image-health, motion, or vendor-specific rule engines.
A Good Example: Analytics Events
One of the most useful parts of this project has been validating whether analytics events are really being exposed over ONVIF.
That sounds obvious, but in practice there are several moving parts:
- the analytic has to be enabled
- the condition has to trigger for long enough to satisfy any validation period
- the camera has to advertise the topic in its event declarations
- the client has to subscribe correctly
- the client has to parse the returned payload accurately
If any one of those layers is off, the result looks the same to the user: “I tested it and nothing showed up.”
The viewer helps break that ambiguity apart by exposing declared topics, logging subscription behavior, and showing live event payloads as they come in.
Design Choices I Wanted To Keep Simple
This project avoids external packages on purpose.
That decision makes the code easier to move between machines and easier to hand to another engineer who just wants to run a script and inspect a camera. It also keeps the implementation educational. You can open the file and see the full path from:
- ONVIF device capability discovery
- event service lookup
- pull-point subscription creation
- pull-message polling
- event parsing and display
For quick support work, lab testing, and field debugging, that simplicity is a feature.
A Few Practical Lessons From Building It
Here are a few takeaways that stood out while refining the viewer:
1. Event parsing needs to be tolerant
Different devices structure event payloads differently. Even something as basic as a timestamp may appear in more than one form. A parser that is too rigid will silently lose useful context.
2. Vendor-specific events are normal
If you only look for generic ONVIF analytics topics, you may miss the actual event a camera is sending. Vendor namespaces and extension topics are a normal part of real-world integrations.
3. Readability is a debugging feature
Formatted XML, searchable event text, and a clean split between summary and raw payload save time. Small UX choices matter a lot when you are investigating a stream in real time.
4. Event declarations are as important as live events
Before blaming the client, it helps to confirm what the camera says it can publish. If the topic is not in the device’s declarations, that usually changes the next troubleshooting step immediately.
Where This Fits
This is not meant to replace a full VMS, a production integration stack, or a mature ONVIF SDK.
It is meant to be a practical engineering tool:
- for diagnosing why events are or are not appearing
- for validating camera analytics output
- for testing ONVIF event subscriptions quickly
- for giving developers a clean starting point when they need to build something more specialized
Final Thought
Sometimes the most useful tools are the ones that remove layers instead of adding them.
This viewer does not try to hide ONVIF behind abstraction. It leans into the protocol just enough to make it inspectable, readable, and useful. For troubleshooting camera events, that turns out to be exactly the right level of complexity.
If you want to explore the project or adapt it for your own environment, the code is small, direct, and easy to extend.