What an Event Server plugin actually is
The XProtect Event Server is the headless Windows service that owns the Rules and Events engine — it ingests events from every source in the system (device events, generic events, other MIP plugins, third-party feeds) and evaluates them against configured rules to drive actions: alarms, notifications, output activation, recording triggers. An Event Server plugin is a MIP SDK plugin that runs inside this process rather than inside Smart Client. It never renders UI of its own — it's server-side, headless, and running whenever the Event Server service is running, independent of whether any operator is logged in anywhere.
This makes it the natural home for translating a third-party system's state into XProtect's event model: a fence controller alarm, a building-management-system fault, a custom business rule, or a scheduled integrity check — anything that should be able to trigger a rule but doesn't originate from a device XProtect already understands. Where our Smart Client plugin guide covers the operator-facing side of the MIP SDK, this one covers the always-on, server-side side of the same SDK.
What the MIP SDK provides for Event Server plugins
The pieces of the SDK relevant here are a different corner of the same assembly set covered in the Smart Client guide:
- VideoOS.Platform.Background — the
Backgroundbase class Event Server plugins inherit from, alongside the sharedPluginDefinitionentry point every MIP plugin type uses. - VideoOS.Platform —
EnvironmentManagerfor registering custom event/alarmKinds and firing them, the item hierarchy for referencing cameras and servers, andConfiguration.Instancefor reading and persisting plugin configuration. - VideoOS.Platform.Messaging — the same publish/subscribe bus Smart Client plugins use, useful when a Background plugin needs to react to system state changes rather than only originate events.
A single plugin assembly can register both a Background plugin and Smart Client plugin types from the same PluginDefinition, sharing a plugin GUID — but the two run in entirely separate processes on potentially separate machines, so treat them as independently deployable components that happen to ship together.
The plugin entry point: PluginDefinition and Background
Event Server plugins share the same PluginDefinition entry point pattern as every other MIP plugin type — Event Server discovers the subclass via reflection when it scans the plugin's assembly, then reads whichever plugin-type lists are populated.
using System;
using System.Collections.Generic;
using VideoOS.Platform;
using VideoOS.Platform.Background;
namespace Xplug.EventServer.Sample
{
public class SamplePluginDefinition : PluginDefinition
{
private static readonly Guid PluginIdValue =
new Guid("4A1E7C2B-9D3F-4E6A-8C1B-2F5A9D0E3B44");
public override Guid Id => PluginIdValue;
public override string Name => "Xplug Event Server Plugin";
public override string VersionString => "1.0.0";
public override string Manufacturer => "Xplug.in";
public override List<Background> BackgroundPlugins =>
new List<Background> { new SampleBackgroundPlugin() };
}
}
using System;
using VideoOS.Platform;
using VideoOS.Platform.Background;
namespace Xplug.EventServer.Sample
{
public class SampleBackgroundPlugin : Background
{
public override Guid Id =>
new Guid("1B2C3D4E-5F60-4718-9A2B-3C4D5E6F7081");
public override string Name => "Xplug Field System Bridge";
public override void Init()
{
// Keep this fast: Event Server waits on every plugin's Init()
// before it finishes starting up. Do polling or slow I/O on
// a thread you own, started here but not awaited here.
EnvironmentManager.Instance.RegisterKind(SampleAlarmKind.Definition);
SampleFieldSystemWorker.Start();
}
public override void Close()
{
SampleFieldSystemWorker.Stop();
}
}
}
As with the Smart Client plugin types, exact base-class members shift slightly between MIP SDK releases — treat the shape above as illustrative of the pattern rather than a drop-in reference, and check the SDK version's own sample projects before committing to a signature.
Firing custom events and driving the Rules engine
A Background plugin earns its place by turning something XProtect doesn't natively understand into something the Rules and Events engine does. That means two things: registering a custom event or alarm Kind so it becomes a selectable trigger in Management Client's Rules and Events configuration, and then firing instances of it when the underlying condition occurs.
using System;
using VideoOS.Platform;
namespace Xplug.EventServer.Sample
{
public static class SampleAlarmKind
{
public static readonly Guid Definition =
new Guid("6E2A9C10-4B3D-4F7E-8A1C-9D2E3F4A5B60");
public static void FireFieldSystemAlarm(string deviceId, string description)
{
var header = new EventHeader
{
EventHeaderGuid = Definition,
Message = description,
Sender = new Item(Guid.Empty, Kind.Server)
};
EnvironmentManager.Instance.FireEvent(header);
}
}
}
Once registered, the custom Kind shows up in Management Client under Rules and Events alongside XProtect's built-in event types, and an administrator can build ordinary rules against it — "when Field System Alarm occurs on Device X, activate output Y and notify group Z" — without knowing or caring that the trigger originated from a plugin rather than a supported device. This is the payoff of building on the Event Server rather than bolting alerting logic directly onto a third-party integration: every downstream capability XProtect already has for its own events (schedules, time constraints, multi-condition rules, alarm escalation) becomes available to your custom one for free.
Threading and reliability inside a shared process
A Background plugin doesn't get its own process or its own fault boundary — it runs inside the same Event Server service instance as every other Background plugin on that server, and as the rule engine evaluating alarms for the entire site. That changes the risk calculus compared to a Smart Client plugin, where a crash affects one operator's session. An unhandled exception on a plugin's own thread, a blocking synchronous call inside an event handler, or a slow Init() that delays service startup all have site-wide blast radius: rules stop evaluating, alarms stop firing, for every camera and every operator, not just the ones related to your integration.
In practice this means: never block inside Init() or inside a message-bus callback — hand off to your own thread or timer immediately; wrap your polling loop's body in a try/catch that logs and continues rather than lets an exception propagate; and treat any third-party call (HTTP, Modbus, a vendor SDK) as something that can hang, with its own timeout, so a single unresponsive field device can't stall the whole plugin.
Deployment: getting a plugin from build to a running Event Server
- Build in Release configuration, matching the target Event Server's .NET Framework version and bitness.
- Copy the output to a subfolder under
%ProgramFiles%\Milestone\XProtect Event Server\MIPPlugins\<YourPluginName>\, including any third-party dependencies. - Restart the Event Server service. On startup it scans
MIPPluginsthe same way Smart Client does, loads each assembly, and instantiates anyPluginDefinitionsubclass it finds. - Verify the load from Management Client's MIP Plugins node, and confirm the custom event/alarm Kind appears as a selectable trigger under Rules and Events.
- Watch the Event Server log during first startup after deployment — a missing dependency or a version mismatch against the installed XProtect release surfaces here, not as a UI error, since there's no UI to show one in.
As with Smart Client plugins, Milestone's verification process is worth planning for early rather than retrofitting — it checks the plugin against a current XProtect version before it runs inside a customer's production Event Server, where the cost of an unstable plugin is the whole rule engine rather than one workstation. It is also the gate for Technology Partner admission and for a Marketplace listing, so it belongs on the schedule as a dependency with a lead time. The full path is in our Technology Partner certification guide.
Where this gets hard in practice
The mechanics above are genuinely enough for a working prototype. What's hard in a production Event Server plugin is everything that only shows up under real load: keeping a polling worker alive across the field system's own outages without leaking threads, designing the custom Kind's payload so it carries enough context for a useful rule without becoming a dumping ground, and handling an Event Server failover cleanly if the deployment runs Event Server in a redundant configuration. This is the part of custom Milestone XProtect plugin development we specialise in at Xplug.in — architecture, Milestone verification, and keeping a Background plugin stable across years of XProtect upgrades, not just the first working build.
Send us the system you need XProtect to react to
- A feasibility answer first, not a proposal. Send the external system’s API documentation, or just describe what should happen in XProtect when it fires. You get back whether an Event Server plugin is the right instrument, what the event model should look like, and what we’d flag before budget is committed.
- An event model designed rather than improvised. Event granularity, severity mapping onto XProtect’s priorities, what becomes an alarm versus a plain event, and how integrators will actually build rules on top of it.
- The plugin built to run unattended for years — reconnection, back-pressure under event storms, threading inside a shared process, and behaviour when the external system goes away mid-shift.
- Source and IP transferred to you at delivery, with the documentation an in-house team needs, plus version tracking as XProtect releases move underneath it.
Xplug.in is a Milestone Technology Partner with 140+ plugins shipped since 2014 — Smart Client views, Event Server integrations, Management Client extensions and Recording Server device drivers. Write to contact@xplug.in or use the form; a straight technical answer costs you one email.
Questions we get asked
When do I need an Event Server plugin rather than a Smart Client one?
Whenever the work has to happen with no operator present. An Event Server plugin runs in a Windows service on the server, so it keeps polling an external system, holding state and raising events whether or not anyone has Smart Client open. A Smart Client plugin only exists while a workstation is running it. Integrations that must not miss an event belong on the server side.
How do custom events reach XProtect’s rules and alarms?
You register a custom event or alarm kind with EnvironmentManager during plugin initialisation, then fire events against it. Once registered, XProtect’s Rules and Events engine treats your events like built-in ones, so integrators can wire them to recording, PTZ presets, outputs or notifications without you writing any of that logic yourself.
What happens to the Event Server if my plugin misbehaves?
It shares the process, so a blocked thread, an unhandled exception on a background thread or an unbounded queue can affect more than your plugin. Treat the Event Server as a shared host: never block its callbacks, own your own threads and cancel them cleanly on Close, bound every queue, and put a throttle in front of anything that could emit thousands of events an hour.
Can an Event Server plugin get video or only events?
It can read video through the MIP SDK — pulling a frame from recorded video is a common pattern for attaching a snapshot to an alarm or an outbound notification. What it cannot do is introduce a new video source into XProtect; getting a device’s live video into the system is a driver concern, not a plugin one.