What a Smart Client plugin actually is
Milestone XProtect Smart Client is the operator-facing console used to view live and recorded video, manage alarms, and work investigations. Out of the box it's a fixed application — but Milestone ships it with an extensibility layer, the MIP SDK (Milestone Integration Platform Software Development Kit), that lets third parties add new functionality without touching Milestone's own code.
A Smart Client plugin is a .NET assembly (a DLL, typically targeting .NET Framework and WPF) that Smart Client discovers and loads at startup from its MIPPlugins folder. Once loaded, the plugin can register one or more plugin types — a new kind of view item that fits inside a camera view grid, a panel docked to the side of the interface, a background service that reacts to events, or a settings page inside Management Client. Every plugin we build at Xplug.in for Milestone XProtect starts from this same extensibility model.
What the MIP SDK provides
The SDK is distributed as a set of .NET assemblies (primarily under the VideoOS.Platform namespace) plus sample projects and documentation, available to registered Milestone MIP partners. The pieces most relevant to Smart Client plugin development are:
- VideoOS.Platform.Client — the base classes for Smart Client extensibility:
PluginDefinition,ViewItemPlugin,ViewItemWpfUserControl,SidePanelPlugin, andBackgroundplugin types. - VideoOS.Platform — configuration access (
Configuration.Instance), the item hierarchy (cameras, servers, views), andEnvironmentManagerfor host/version information. - VideoOS.Platform.Messaging — a publish/subscribe message bus used to pass events between your plugin's components and to react to Smart Client state changes (view changed, item selected, and so on).
Beyond Smart Client, the same SDK covers Event Server plugins (custom event and alarm sources), Recording Server device driver plugins, and Management Client property-page plugins — but this guide focuses on the Smart Client side, which is where most bespoke operator-facing capability gets built.
The plugin entry point: PluginDefinition
Every MIP plugin assembly needs exactly one class that inherits from the abstract PluginDefinition base class. This is the entry point Smart Client instantiates on startup — it identifies the plugin and tells the host application which plugin types it contributes.
using System;
using System.Collections.Generic;
using System.Drawing;
using VideoOS.Platform.Client;
namespace Xplug.SmartClient.Sample
{
public class SamplePluginDefinition : PluginDefinition
{
private static readonly Guid PluginIdValue =
new Guid("6E9C2C2A-6B0A-4B0B-9C2E-2B6F3A7D5E11");
public override Guid Id => PluginIdValue;
public override string Name => "Xplug Sample Plugin";
public override string VersionString => "1.0.0";
public override string Manufacturer => "Xplug.in";
public override List<ViewItemPlugin> ViewItemPlugins =>
new List<ViewItemPlugin> { new SampleViewItemPlugin() };
public override List<SidePanelPlugin> SidePanelPlugins =>
new List<SidePanelPlugin> { new SampleSidePanelPlugin() };
}
}
Smart Client finds this class through reflection when it scans the assembly, so there's no separate registration file to maintain — the PluginDefinition subclass is the manifest. From here, every capability the plugin exposes is declared as a list Smart Client reads on load.
Registering a view item with ViewItemPlugin
A view item is anything an operator can drag into a Smart Client view grid alongside camera panes — a map, a custom dashboard, a search widget. To add a new one, you implement ViewItemPlugin, which describes the item (name, icon, category) and produces the actual WPF control that gets hosted inside the view cell.
using System;
using System.Drawing;
using VideoOS.Platform.Client;
namespace Xplug.SmartClient.Sample
{
public class SampleViewItemPlugin : ViewItemPlugin
{
public override string Name => "Xplug Analytics Panel";
public override Guid Kind => new Guid("2B7C1E10-4C3A-4A7E-9C1D-8E2F6A0B9C33");
public override Guid ScreenSize => ViewItemManager.Size1x1;
public override ViewItemWpfUserControl GenerateViewItemWpfUserControl()
{
return new SampleViewItemWpfUserControl();
}
public override Image Icon => Properties.Resources.PluginIcon;
}
public class SampleViewItemWpfUserControl : ViewItemWpfUserControl
{
public SampleViewItemWpfUserControl()
{
InitializeComponent();
}
public override void Init()
{
// Called once the item has an assigned FQID (the camera,
// view, or item the operator dropped the plugin onto).
base.Init();
}
}
}
The ViewItemWpfUserControl is a regular WPF UserControl under the hood, so anything you'd normally build in WPF — data binding, custom controls, third-party UI libraries — works inside it. What MIP SDK adds is the lifecycle: Init() fires once the control has a Fully Qualified ID (FQID) bound to it, which is how your plugin knows which camera, server, or view item it's actually attached to in that specific view.
Side panels for persistent, view-independent UI
Not every capability belongs inside a view cell. Alarm lists, bookmark managers, and search tools in stock Smart Client are all side panels — UI docked to the edge of the window that stays visible regardless of which view the operator is looking at. SidePanelPlugin follows the same pattern as ViewItemPlugin: declare a name and icon, then hand back the WPF control Smart Client should dock.
using System.Drawing;
using VideoOS.Platform.Client;
namespace Xplug.SmartClient.Sample
{
public class SampleSidePanelPlugin : SidePanelPlugin
{
public override string Name => "Xplug Alerts";
public override Image Icon => Properties.Resources.SidePanelIcon;
public override SidePanel GenerateSidePanel()
{
return new SampleSidePanel();
}
}
}
Side panels are the right fit for anything an operator needs on standby — a live alert feed, a rules dashboard, a chat channel to a response team — rather than something tied to a specific camera or view.
Deployment: getting a plugin from build to running Smart Client
Once the plugin builds cleanly against the SDK's reference assemblies, deployment is largely a matter of getting the DLL (and its dependencies) into the right folder:
- Build in Release configuration, matching the target Smart Client's bitness (x64 for current XProtect releases) and .NET Framework version.
- Copy the output to a subfolder under
%ProgramFiles%\Milestone\XProtect Smart Client\MIPPlugins\<YourPluginName>\, including any third-party dependencies the plugin references. - Restart Smart Client. On startup it scans
MIPPlugins, loads each assembly, and instantiates anyPluginDefinitionsubclass it finds. - Verify the load via Smart Client's About/plugin information dialog, or by checking the client-side MIP SDK log for load errors — a missing dependency or version mismatch against the installed XProtect release is the most common failure at this step.
- For fleet rollout, package the plugin as an MSI or use your existing software-distribution tooling so the same build lands identically across every operator workstation — version drift between Smart Client instances is the single biggest cause of "works on my machine" plugin bugs.
For anything beyond a proof of concept, plan on Milestone's verification process, which checks the plugin's compatibility against a current XProtect version before it reaches a customer's production environment. It is also the gate for the rest of the ecosystem: at least one successfully verified integration is what admits a company to the Technology Partner Program, and verification is what a Marketplace listing is based on. The full path is in our Technology Partner certification guide.
Where this gets hard in practice
The patterns above cover the mechanical side of MIP SDK plugin development, and they're genuinely all you need for a prototype. Where projects usually get harder is everything around that skeleton: handling reconnects and view-switching cleanly inside ViewItemWpfUserControl.Init(), keeping a side panel's state in sync across multiple open Smart Client windows, managing configuration through Configuration.Instance without blocking the UI thread, and packaging a plugin so it survives a Milestone version upgrade without breaking.
This is the part of custom Milestone XProtect plugin development we specialise in at Xplug.in — architecture, Milestone verification, and long-term version tracking across XProtect releases, not just the first working build.
Send us the workflow you need in Smart Client, and we’ll tell you if it fits
- A feasibility answer first, not a proposal. Describe the operator workflow you want inside Smart Client. You get back which plugin types it needs, what the client will and won’t let a plugin do, and the constraints we’d flag before any budget is committed.
- An architecture document before code. Which extension points carry which part of the UI, where state lives, how configuration reaches the workstation, and what happens when the plugin is on a machine the integrator forgot to update.
- The plugin built and certified against real XProtect installations rather than a demo rig, and taken through Milestone’s certification process instead of left working-but-unverified.
- 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
Which plugin type should a Smart Client feature use?
It depends on where the operator needs it. A ViewItemPlugin occupies a tile in the view layout, which suits anything that sits alongside video as a peer — a map, a status board, a data panel. A SidePanelPlugin adds a panel beside the view, better for controls and lists that stay available while the operator changes views. A workspace or toolbar contribution suits actions rather than surfaces. Most real plugins use more than one, and the mistake to avoid is forcing a whole application into a single view item.
Can a Smart Client plugin work without an Event Server plugin?
Yes, and plenty do. A client-only plugin is a complete product if everything it needs is available to the workstation — configuration, a third-party API it can reach, and video from the recorder. You need a server-side Event Server plugin when work must continue whether or not an operator has Smart Client open: polling an external system, holding state centrally, or raising events into the Rules engine.
How is a Smart Client plugin deployed to fifty workstations?
By dropping the plugin’s assemblies into the MIPPlugins folder on each machine — which means a site with fifty Smart Clients is a software distribution problem, not a copy-paste one. Ship an installer with a silent or unattended mode so it can be pushed through the customer’s existing deployment tooling, and never document a manual file copy as the supported path.
Will a plugin written today survive the next XProtect upgrade?
Usually, but not for free. MIP SDK base-class members shift between releases, so a plugin pinned to an old SDK can compile against APIs that later change shape. Plan on tracking XProtect releases deliberately: test against each new version, keep the plugin’s SDK reference current, and publish the version matrix you have actually tested rather than implying every version works.