Files
PowerToys/doc/devdocs/events.md
Jessica Dene Earley-Cha 3f3e04086e Add developer documentation for implementing telemetry events in PowerToys modules. (#44912)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Adds a new doc (`doc/devdocs/Events.md`) that walks developers through
how to add telemetry events to PowerToys with next steps of reaching out
to Carlos or Jessica.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-10 11:22:51 -08:00

6.9 KiB
Raw Blame History

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 usergenerated 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
    2. Add the new event(s) DATA_AND_PRIVACY.md
  2. 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 Declares the global ETW provider g_hProvider
TraceBase.h Base class with RegisterProvider(), UnregisterProvider(), and IsDataDiagnosticsEnabled() check
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):

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

    // 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 Wraps TraceLoggingWrite with IsDataDiagnosticsEnabled() check
ProjectTelemetryPrivacyDataTag(tag) TraceLoggingDefines.h Sets privacy classification

C# Telemetry Implementation

Core Components

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

Pattern for C# Modules

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

    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:

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

Privacy Tags (C#)

Tag Use Case
PartA_PrivTags.ProductAndServiceUsage TelemetryBase.cs Feature usage events
PartA_PrivTags.ProductAndServicePerformance TelemetryBase.cs Performance/timing events

Update DATA_AND_PRIVACY.md file

Add your new event(s) to 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
  2. Ship the change in a PowerToys release
  3. Reach out for next steps