# Adding Telemetry Events Using the PowerToys Telemetry Framework: A Developer’s Guide

> Learn to add telemetry events using the PowerToys telemetry framework. Follow this developer guide to create and emit events efficiently.

- Repository: [Microsoft/PowerToys](https://github.com/microsoft/PowerToys)
- Tags: how-to-guide
- Published: 2026-02-25

---

**To add telemetry events using the PowerToys telemetry framework, create a class inheriting from `EventBase` and implementing `IEvent`, decorate it with `[EventData]`, then emit it via `PowerToysTelemetry.Log.WriteEvent()`.**

The PowerToys telemetry framework provides a lightweight, ETW-based system for tracking feature usage and diagnostic data within the Microsoft PowerToys repository. This guide explains how to instrument your code by defining custom event classes and publishing them through the singleton telemetry helper.

## Understanding the PowerToys Telemetry Architecture

The telemetry system resides primarily in the **ManagedTelemetry** project and relies on Event Tracing for Windows (ETW) to emit structured data. Understanding the core components ensures you implement events that integrate seamlessly with the existing pipeline.

### Core Components

| Component | Role | Source Location |
|-----------|------|-----------------|
| `PowerToysTelemetry` | Singleton helper that writes events to the **Microsoft.PowerToys** ETW provider. | [`src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs`](https://github.com/microsoft/PowerToys/blob/main/src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs) |
| `EventBase` | Base class supplying common properties (`EventName`, `Version`, etc.) for every payload. | [`src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs`](https://github.com/microsoft/PowerToys/blob/main/src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs) |
| `IEvent` + `[EventData]` | Marker interface and attribute telling the serializer how to process the payload. | [`src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs`](https://github.com/microsoft/PowerToys/blob/main/src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs) |
| Concrete Event classes | One per logical action (e.g., `CmdNotFoundInstallEvent`). They inherit `EventBase`, implement `IEvent`, and typically live in `src/settings-ui/Settings.UI.Library/Telemetry/Events`. | [`src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundInstallEvent.cs`](https://github.com/microsoft/PowerToys/blob/main/src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundInstallEvent.cs) |

### How Telemetry Flows Through the System

The framework follows a three-stage pipeline:

1. **Event Definition** – You create a class deriving from `EventBase` and implementing `IEvent`. The `[EventData]` attribute ensures the ETW serializer recognizes the class, while `PartA_PrivTags` properties indicate privacy classifications.

2. **Publishing** – Your UI or module logic calls `PowerToysTelemetry.Log.WriteEvent<T>()`, passing an instance of your event class. The method checks the global diagnostic flag (`DataDiagnosticsSettings.GetEnabledValue()`) before forwarding the payload to `TelemetryBase.Write<T>()`, which emits the actual ETW event.

3. **Consumption** – The ETW provider captures the event locally. When users opt into diagnostic data collection, the pipeline aggregates these events and transmits them to Microsoft for analysis.

## Step-by-Step Guide to Adding Telemetry Events

Implementing new telemetry requires defining the payload structure and instrumenting your code to fire the event at the appropriate moment.

### Step 1: Define Your Event Class

Create a new class file in the appropriate `Telemetry/Events` folder (e.g., `src/settings-ui/Settings.UI.Library/Telemetry/Events/` for settings UI features). The class must inherit `EventBase`, implement `IEvent`, and include the `[EventData]` attribute.

```csharp
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;

namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events
{
    [EventData]
    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
    public class MyFeatureUsedEvent : EventBase, IEvent
    {
        // Required privacy tag indicating this is product usage data
        public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;

        // Custom payload properties
        public string FeatureName { get; set; }
        public bool WasSuccessful { get; set; }

        public MyFeatureUsedEvent()
        {
            EventName = nameof(MyFeatureUsedEvent);
        }
    }
}

```

The `PartA_PrivTags` property is mandatory for privacy compliance, categorizing the event as either `ProductAndServiceUsage` or `ProductAndServicePerformance`. The `[DynamicallyAccessedMembers]` attribute ensures the trimmer preserves the public properties required for ETW serialization.

### Step 2: Emit the Event from Your Code

In your ViewModel, command handler, or module logic, instantiate the event class and pass it to the singleton `PowerToysTelemetry.Log.WriteEvent()` method.

```csharp
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;

public void OnUserClickedMyFeature()
{
    var telemetryEvent = new MyFeatureUsedEvent
    {
        FeatureName = "SuperCoolTool",
        WasSuccessful = true
    };

    PowerToysTelemetry.Log.WriteEvent(telemetryEvent);
}

```

The `WriteEvent<T>` method automatically checks whether the user has enabled diagnostic data collection via `DataDiagnosticsSettings.GetEnabledValue()` before writing to the ETW provider, ensuring compliance with user privacy preferences.

### Real-World Example from the PowerToys Codebase

The **Command Not Found** module demonstrates this pattern in production. When a user installs the module, the ViewModel fires a `CmdNotFoundInstallEvent`:

```csharp
// Located in src/settings-ui/Settings.UI/ViewModels/CmdNotFoundViewModel.cs
PowerToysTelemetry.Log.WriteEvent(new CmdNotFoundInstallEvent());

```

The corresponding event definition in [`src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundInstallEvent.cs`](https://github.com/microsoft/PowerToys/blob/main/src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundInstallEvent.cs) inherits from `EventBase`, implements the required privacy tags, and requires no additional payload properties for this specific action.

## Key Files and Locations in the Repository

When implementing telemetry, reference these specific files to understand the underlying implementation and existing patterns:

| Path | Purpose |
|------|---------|
| [`src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs`](https://github.com/microsoft/PowerToys/blob/main/src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs) | Singleton entry point containing the `Log` property and `WriteEvent<T>` method. |
| [`src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs`](https://github.com/microsoft/PowerToys/blob/main/src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs) | Abstract base class providing `EventName`, versioning, and `IEvent` implementation. |
| [`src/common/ManagedTelemetry/Telemetry/Events/DebugEvent.cs`](https://github.com/microsoft/PowerToys/blob/main/src/common/ManagedTelemetry/Telemetry/Events/DebugEvent.cs) | Reference implementation showing basic event structure with privacy tags. |
| `src/settings-ui/Settings.UI.Library/Telemetry/Events/` | Directory containing UI-specific events like [`CmdNotFoundInstallEvent.cs`](https://github.com/microsoft/PowerToys/blob/main/CmdNotFoundInstallEvent.cs). |
| `src/settings-ui/Settings.UI/ViewModels/` | Location of ViewModel call sites (e.g., [`CmdNotFoundViewModel.cs`](https://github.com/microsoft/PowerToys/blob/main/CmdNotFoundViewModel.cs)) demonstrating event emission. |
| [`src/common/ManagedTelemetry/Telemetry/TelemetryBase.cs`](https://github.com/microsoft/PowerToys/blob/main/src/common/ManagedTelemetry/Telemetry/TelemetryBase.cs) | Low-level ETW write mechanics and diagnostic flag checking. |

## Summary

- **PowerToys telemetry** relies on an ETW-based framework located in the `ManagedTelemetry` project, using the `Microsoft.PowerToys` provider.
- **Event classes** must inherit from `EventBase`, implement `IEvent`, use the `[EventData]` attribute, and specify `PartA_PrivTags` for privacy compliance.
- **Emission** occurs through the singleton `PowerToysTelemetry.Log.WriteEvent<T>()` method, which automatically respects user diagnostic preferences.
- **UI events** typically reside in `src/settings-ui/Settings.UI.Library/Telemetry/Events/`, while module-specific events follow similar patterns in their respective directories.

## Frequently Asked Questions

### What is ETW and why does PowerToys use it for telemetry?

Event Tracing for Windows (ETW) is a high-performance logging mechanism built into Windows that allows applications to emit structured events with minimal overhead. PowerToys uses ETW through the `Microsoft.PowerToys` provider because it provides reliable, low-latency telemetry collection that integrates with standard Windows diagnostic tools and respects user privacy controls through the system's data diagnostic settings.

### How do I ensure my telemetry events comply with privacy requirements?

Every event class must implement the `PartA_PrivTags` property, returning either `PartA_PrivTags.ProductAndServiceUsage` for feature interaction data or `PartA_PrivTags.ProductAndServicePerformance` for diagnostic data. Additionally, the `PowerToysTelemetry.Log.WriteEvent()` method automatically checks `DataDiagnosticsSettings.GetEnabledValue()` before writing to ETW, ensuring events are only captured when users have explicitly opted into diagnostic data collection.

### Can I add telemetry to C++ modules, or is this framework C# only?

The `ManagedTelemetry` project and the `PowerToysTelemetry` class are specifically designed for managed (.NET) code. C++ modules in the PowerToys repository typically use different telemetry mechanisms or call into separate native ETW providers. If you are working with a C++ module, you should look for existing native telemetry patterns in that specific project's source code rather than using the C# `EventBase` framework described here.

### Where can I view the telemetry events locally for debugging?

Since PowerToys uses ETW, you can capture and view telemetry events locally using tools like **PerfView** or the Windows **Event Viewer** (under Applications and Services Logs > Microsoft > PowerToys). During development, you can also set breakpoints in `PowerToysTelemetry.Log.WriteEvent()` located in [`src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs`](https://github.com/microsoft/PowerToys/blob/main/src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs) to verify that your events are being constructed and emitted correctly before they reach the ETW provider.