# Telemetry Events

PowerToys collects limited telemetry to understand feature usage, reliability, and product quality. When adding a new telemetry event, follow the steps below to ensure the event is properly declared, documented, and available after release.

**⚠️ Important**: Telemetry must never include personal information, file paths, or user‑generated content.

## Developer Effort Overview (What to Expect)

Adding a telemetry event is a **multi-step process** that typically spans several areas of the codebase and documentation.

At a high level, developers should expect to:

1. Within one PR:
    1. Add a new telemetry event(s) to module
    1. Add the new event(s) DATA_AND_PRIVACY.md
1. Reach out to @carlos-zamora or @chatasweetie so internal scripts can process new event(s)

### Privacy Guidelines

**NEVER** log:

- User data (text, files, emails, etc.)
- File paths or filenames
- Personal information
- Sensitive system information
- Anything that could identify a specific user

DO log:

- Feature usage (which features, how often)
- Success/failure status
- Timing/performance metrics
- Error types (not error messages with user data)
- Aggregate counts

### Event Naming Convention

Follow this pattern: `UtilityName_EventDescription`

Examples:

- `ColorPicker_Session`
- `FancyZones_LayoutApplied`
- `PowerRename_Rename`
- `AdvancedPaste_FormatClicked`
- `CmdPal_ExtensionInvoked`

## Adding Telemetry Events to PowerToys

PowerToys uses ETW (Event Tracing for Windows) for telemetry in both C++ and C# modules. The telemetry system is:

- Opt-in by default (disabled since v0.86)
- Privacy-focused - never logs personal info, file paths, or user-generated content
- Controlled by registry - HKEY_CURRENT_USER\Software\Classes\PowerToys\AllowDataDiagnostics

### C++ Telemetry Implementation

**Core Components**

| File  | Purpose |
| ------------- |:-------------:|
| [ProjectTelemetry.h](../../src/common/Telemetry/ProjectTelemetry.h)    | Declares the global ETW provider g_hProvider     |
| [TraceBase.h](../../src/common/Telemetry/TraceBase.h)      | Base class with RegisterProvider(), UnregisterProvider(), and IsDataDiagnosticsEnabled() check     |
| [TraceLoggingDefines.h](../../src/common/Telemetry/TraceLoggingDefines.h)      | Privacy tags and telemetry option group macros


#### Pattern for C++ Modules

1. Create a `Trace` class inheriting from `telemetry::TraceBase` (src/common/Telemetry/TraceBase.h):

    ```c
    // trace.h
    #pragma once
    #include <common/Telemetry/TraceBase.h>
    
    class Trace : public telemetry::TraceBase
    {
    public:
        static void MyEvent(/* parameters */);
    };
    ```

2. Implement events using `TraceLoggingWriteWrapper`:

    ```cpp
    // trace.cpp
    #include "trace.h"
    #include <common/Telemetry/TraceBase.h>
    
    TRACELOGGING_DEFINE_PROVIDER(
        g_hProvider,
        "Microsoft.PowerToys",
        (0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
        TraceLoggingOptionProjectTelemetry());
    
    void Trace::MyEvent(bool enabled)
    {
        TraceLoggingWriteWrapper(
            g_hProvider,
            "ModuleName_EventName",           // Event name
            TraceLoggingBoolean(enabled, "Enabled"),  // Event data
            ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
            TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
            TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
    }
    ```

**Key C++ Telemetry Macros**

| Macro  | Purpose |
| ------------- |:-------------:|
| `TraceLoggingWriteWrapper` [CustomAction.cpp](../../installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp)     | Wraps `TraceLoggingWrite` with `IsDataDiagnosticsEnabled()` check     |
| `ProjectTelemetryPrivacyDataTag(tag)` [TraceLoggingDefines.h](../../src/common/Telemetry/TraceLoggingDefines.h)     | Sets privacy classification |

### C# Telemetry Implementation

**Core Components**

| File  | Purpose |
| ------------- |:-------------:|
| [PowerToysTelemetry.cs](../../src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs)    | Singleton `Log` instance with `WriteEvent<T>()` method     |
| [EventBase.cs](../../src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs)      | Base class for all events (provides `EventName`, `Version`)     |
| [IEvent.cs](../../src/common/ManagedTelemetry/Telemetry/Events/IEvent.cs)     | Interface requiring `PartA_PrivTags` property     |
| [TelemetryBase.cs](../../src/common/Telemetry/TelemetryBase.cs)     | 	Inherits from `EventSource`, defines ETW constants     |
| [DataDiagnosticsSettings.cs](../../src/common/ManagedTelemetry/Telemetry/DataDiagnosticsSettings.cs)     | Registry-based enable/disable check 

#### Pattern for C# Modules

1. Create an event class inheriting from `EventBase` and implementing `IEvent`:

    ```csharp
    using System.Diagnostics.CodeAnalysis;
    using System.Diagnostics.Tracing;
    using Microsoft.PowerToys.Telemetry;
    using Microsoft.PowerToys.Telemetry.Events;
    
    namespace MyModule.Telemetry
    {
        [EventData]
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
        public class MyModuleEvent : EventBase, IEvent
        {
            // Event properties (logged as telemetry data)
            public string SomeProperty { get; set; }
            public int SomeValue { get; set; }
    
            // Required: Privacy tag
            public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
    
            // Optional: Set EventName in constructor (defaults to class name)
            public MyModuleEvent(string prop, int val)
            {
                EventName = "MyModule_EventName";
                SomeProperty = prop;
                SomeValue = val;
            }
        }
    }
    ```

2. Log the event:

```csharp
PowerToysTelemetry.Log.WriteEvent(new MyModuleEvent("value", 42));
```

**Privacy Tags (C#)**

| Tag  | Use Case |
| ------------- |:-------------:|
| `PartA_PrivTags.ProductAndServiceUsage`  [TelemetryBase.cs](../../src/common/Telemetry/TelemetryBase.cs)     | Feature usage events
| `PartA_PrivTags.ProductAndServicePerformance` [TelemetryBase.cs](../../src/common/Telemetry/TelemetryBase.cs)     | Performance/timing events
  
### Update DATA_AND_PRIVACY.md file

Add your new event(s) to [DATA_AND_PRIVACY.md](../../DATA_AND_PRIVACY.md).

## Launch Product Version Containing the new events

Events do not become active until they ship in a released PowerToys version. After your PRs are merged:

- The event will begin firing once users install the version that includes it
- In order for PowerToys to process these events, you must complete the next section

## Next Steps

Reach out to @carlos-zamora or @chatasweetie so internal scripts can process new event(s).

## Summary

Required steps:

1. In one PR:
    - Add the event(s) in code
    - Document event(s) in DATA_AND_PRIVACY.md
1. Ship the change in a PowerToys release
1. Reach out for next steps
