Most RPA guides ignore the system tray — but that's exactly where many legacy business apps communicate their status. Learn how to detect tray icon states, capture balloon notifications before they vanish, and trigger flow logic based on system tray events using Power Automate Desktop and PowerShell.

Picture this: your organization runs a legacy data synchronization tool that lives entirely in the Windows system tray. It has no API, no webhook, no database you can query. The only signal it gives the outside world is a balloon notification that pops up when a sync completes — or an icon color change when it encounters an error. Your job is to build an automation that catches that signal, reads it, and kicks off downstream processing in Excel and a web portal. No human watching the screen required.
This is not an edge case. Across industries, critical business applications communicate their status almost exclusively through the Windows notification area. VPN clients, antivirus tools, backup software, ERP agents, and custom middleware all use tray icons and balloon tooltips as their primary status channel. If you're building production RPA flows on Windows machines, you will encounter this problem — and the naive approaches (wait a fixed number of seconds, hope for the best) will fail you in production.
By the end of this lesson, you'll have the skills to build flows that actively monitor the system tray, read icon tooltips and states programmatically, intercept balloon notifications before they disappear, and branch your flow logic based on what those notifications actually say. We'll combine Power Automate Desktop's native UI automation with PowerShell scripting to cover scenarios where PAD's built-in actions aren't enough on their own.
What you'll learn:
This lesson assumes you're comfortable with the PAD designer, can build basic flows with variables and loops, and have at least some exposure to UI element selectors. If you need a refresher on selectors specifically, the lesson on UI Elements and Selectors in Power Automate Desktop: Building Automations That Don't Break covers the fundamentals you'll need here. You should also understand how error handling works in PAD — we'll rely on it heavily when tray interactions go sideways. Review Error Handling in Desktop Flows: On Block Error, Retry Policies, and Recovery Screenshots if you need a refresher.
Before you write a single action, you need to understand what you're actually targeting. The Windows notification area (the tray) is a region of the taskbar managed by explorer.exe. It hosts two kinds of content: persistent icons (apps that are running and want to show ongoing status) and transient notifications (balloon tips or modern toast notifications that appear for a few seconds and vanish).
From an automation standpoint, these are fundamentally different problems:
Persistent tray icons are actual UI elements in a toolbar control. You can reach them with UI automation, read their name (tooltip), check their existence, and right-click them to trigger context menus — as long as you know their selector.
Balloon notifications are a race condition. They appear for 5–10 seconds by default and disappear whether you interact with them or not. This means your flow needs to be either pre-positioned and waiting, or fast enough to react within that window.
Modern toast notifications (the ones that stack in Action Center) are a different beast still — they're rendered by the shell's notification platform and can actually be queried even after they've disappeared, which gives us more options.
Key insight
The Windows system tray toolbar is a ToolBar control accessible via UI Automation. Its children are Button elements where the button name is the tooltip text of the tray icon. This is why reading tooltip text is actually straightforward once you have the right selector path.
The tray toolbar lives inside the taskbar window. The internal control hierarchy looks roughly like this:
Shell_TrayWnd (the taskbar window)
└─ TrayNotifyWnd
└─ SysPager
└─ ToolbarWindow32 ("Notification Area")
├─ Button ("OneDrive - Personal\nUp to date")
├─ Button ("VPN Connected - Corp Network")
└─ Button ("DataSync Agent - Last sync: 2:45 PM")
There's a second overflow toolbar inside the "Show hidden icons" flyout, with the same structure. Apps that Windows decides are "lower priority" get pushed there. Your automation needs to handle both locations.
Let's start with the concrete mechanics of targeting a tray icon. Open the Power Automate Desktop designer and we'll walk through building the selector.
First, make sure the icon you want to target is visible. If it lives in the overflow area, click the chevron (the upward arrow on the taskbar) to open the hidden icons flyout before you start capturing. PAD's UI recorder can only capture elements that are currently visible on screen.
Use the "Add UI element" picker (the crosshair button in the UI elements panel). Hover over the specific tray icon — you should see the highlight border snap around just that button. Press Ctrl+Left Click to capture it.
The resulting selector will look something like this in PAD's selector editor:
:desktop > window[Name="Taskbar" OR Name="Shell_TrayWnd"] >
custom[AutomationId="TrayNotifyWnd"] >
custom[AutomationId="SysPager"] >
toolbar[Name="Notification Area"] >
button[Name="DataSync Agent - Last sync: 2:45 PM"]
Warning
That button[Name="..."] attribute is the tooltip text, and it changes every time the sync completes (because the timestamp updates). If you leave the selector as-is, it will fail the next time you run it. You have two options: use a partial match on a stable prefix, or target the icon by its ordinal position if the icon order is predictable.
In PAD's selector editor, switch the Name attribute on the button from an exact match to a "Contains" match. If your selector editor supports regular expressions, use DataSync Agent as the match string. The selector becomes:
:desktop > window[Name="Taskbar" OR Name="Shell_TrayWnd"] >
custom[AutomationId="TrayNotifyWnd"] >
custom[AutomationId="SysPager"] >
toolbar[Name="Notification Area"] >
button[Name contains "DataSync Agent"]
Now it will match regardless of what timestamp is appended.
Once you have the element captured, use the Get details of UI element in window action with the property set to Name. This returns the full tooltip string, including any dynamic content like status messages or timestamps. Store this in a variable — TrayIconTooltip — for use in your flow logic.
Here's how that action block looks in structured pseudocode:
Get details of UI element in window
UI element: TrayIcon_DataSyncAgent
Attribute: Name
Store result in: TrayIconTooltip
For most real workflows, you don't want to read the tray icon once and move on — you want to watch it until something changes. This means building a polling loop.
The classic pattern is a Loop with a Wait action inside, checking a condition on each iteration. Here's a complete polling flow that watches the DataSync Agent icon and exits the loop when it detects either a "Sync complete" or "Error" status:
SET MaxWaitSeconds TO 300
SET PollIntervalSeconds TO 5
SET ElapsedSeconds TO 0
SET SyncStatus TO "Unknown"
LOOP
# Try to read the tray icon tooltip
ON BLOCK ERROR
SET TrayIconFound TO False
END
Get details of UI element in window
UI element: TrayIcon_DataSyncAgent
Attribute: Name
Store result in: TrayIconTooltip
SET TrayIconFound TO True
IF TrayIconTooltip CONTAINS "Sync complete" THEN
SET SyncStatus TO "Complete"
EXIT LOOP
END IF
IF TrayIconTooltip CONTAINS "Error" OR TrayIconTooltip CONTAINS "Failed" THEN
SET SyncStatus TO "Error"
EXIT LOOP
END IF
Wait PollIntervalSeconds seconds
SET ElapsedSeconds TO ElapsedSeconds + PollIntervalSeconds
IF ElapsedSeconds >= MaxWaitSeconds THEN
SET SyncStatus TO "Timeout"
EXIT LOOP
END IF
END LOOP
Tip
Set your poll interval based on how quickly the application updates its tray icon. For most business tools, 5 seconds is a reasonable default that's responsive without hammering the UI automation framework. For high-frequency monitoring (sub-second), you'll want PowerShell instead.
After the loop, SyncStatus will be one of "Complete", "Error", or "Timeout", and you can branch your downstream logic accordingly. This is much cleaner than building deeply nested If blocks.
Here's where a lot of automations break: if the icon you're monitoring lives in the hidden icons overflow area, it won't be in the main toolbar — it'll be in a separate flyout window that only exists when open. You need to open it first.
Add a block before your polling loop:
# Check if icon is in main tray first
ON BLOCK ERROR
# Icon not in main tray, try overflow
Click UI element: ShowHiddenIcons_Button
# This clicks the chevron/arrow to open the overflow
Wait 1 second
# Now capture from the overflow toolbar
END
The overflow flyout window has a different selector root:
:desktop > window[Name="Overflow Notification Area"] >
toolbar[Name="Overflow Notification Area"] >
button[Name contains "DataSync Agent"]
Warning
The overflow flyout closes automatically when it loses focus, and PAD's UI automation actions can sometimes cause focus loss. If your icon is in the overflow, consider using PowerShell to query the tray state instead — it doesn't require the flyout to be open. We'll cover that approach in the PowerShell section below.
Balloon notifications are the harder problem. They appear briefly and disappear. The naive approach — "take a screenshot and OCR it" — is flaky because the timing is unpredictable. Let's look at more reliable strategies.
If you know roughly when a balloon will appear, you can set up a loop that's actively looking for the balloon window. Balloon tips in classic Win32 applications create a tooltips_class32 window. Modern applications use toast notifications via Windows.UI.Notifications.
For classic balloon tips, set up a window-existence check loop:
SET BalloonCaptured TO False
SET BalloonCheckCount TO 0
SET MaxBalloonChecks TO 60 # 60 * 0.5 seconds = 30 second window
LOOP WHILE BalloonCheckCount < MaxBalloonChecks AND BalloonCaptured = False
IF window exists [Class="tooltips_class32"] THEN
Get details of UI element in window
Window: tooltips_class32
Element: static text
Attribute: Name
Store in: BalloonText
SET BalloonCaptured TO True
END IF
Wait 0.5 seconds
SET BalloonCheckCount TO BalloonCheckCount + 1
END LOOP
Note
The tooltips_class32 window class is used by older Win32 applications for balloon tips. Applications built with newer frameworks (WPF, WinUI, modern Electron apps) use completely different notification mechanisms. If your target app uses toast notifications, skip ahead to the toast approach.
Modern Windows toast notifications have a significant advantage over balloon tips: they're logged in the notification platform's history, and you can query that history even after the notification has been dismissed. This completely eliminates the race condition.
Use PAD's Run PowerShell script action with this script:
# Query Windows notification history for notifications from a specific app
Add-Type -AssemblyName System.Runtime.WindowsRuntime
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() |
Where-Object { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and
$_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[0]
Function Await($WinRtTask, $ResultType) {
$asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
$netTask = $asTask.Invoke($null, @($WinRtTask))
$netTask.Wait(-1) | Out-Null
$netTask.Result
}
[Windows.UI.Notifications.Management.UserNotificationListener, Windows.UI.Notifications.Management, ContentType = WindowsRuntime] | Out-Null
[Windows.UI.Notifications.UserNotificationChangedKind, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
$listener = [Windows.UI.Notifications.Management.UserNotificationListener]::Current
$notificationsAsync = $listener.GetNotificationsAsync(
[Windows.UI.Notifications.NotificationKinds]::Toast
)
$notifications = Await $notificationsAsync ([System.Collections.Generic.IReadOnlyList[Windows.UI.Notifications.UserNotification]])
# Filter by app name and get the most recent
$targetNotifications = $notifications | Where-Object {
$_.AppInfo.DisplayInfo.DisplayName -like "*DataSync*"
} | Sort-Object { $_.CreationTime } -Descending
if ($targetNotifications.Count -gt 0) {
$latest = $targetNotifications[0]
$toast = $latest.Notification.Visual.GetBinding(
[Windows.UI.Notifications.KnownNotificationBindings]::ToastGeneric
)
if ($toast -ne $null) {
$textElements = $toast.GetTextElements()
$output = ($textElements | ForEach-Object { $_.Text }) -join "|"
Write-Output $output
}
} else {
Write-Output "NO_NOTIFICATION_FOUND"
}
Capture the output in PAD using the PowershellOutput variable that the Run PowerShell script action returns. Parse it by splitting on | to get individual text lines from the notification.
This approach is much more reliable for production flows. The notification history is retained even after dismissal, so you don't have to win a timing race.
Key insight
The UserNotificationListener API requires that your app (in this case, the PowerShell process) has been granted access permission by the user. The first time this runs, Windows may prompt for permission. In unattended scenarios, pre-grant this access manually or through group policy before deploying your flow.
For more on integrating PowerShell into your PAD flows, see Scripting Inside Desktop Flows: Running PowerShell, Python, and VBScript Actions.
Sometimes you don't just need to read a tray icon's status — you need to interact with it. Right-clicking a tray icon opens a context menu. Here's how to do that reliably.
Right-click UI element: TrayIcon_DataSyncAgent
# Wait for context menu to appear
Wait for UI element to exist: ContextMenu_DataSync
Timeout: 5 seconds
# Click specific menu item
Click UI element: MenuItem_ForceSyncNow
The tricky part is that context menus are transient windows that don't appear in your UI element tree until they're visible. Capture the context menu items while the menu is open (right-click manually to open it, then use "Add UI element" to capture the items), and the selector will work when your flow triggers it programmatically.
Tip
Right-click context menus on tray icons sometimes require a brief delay between the right-click and the menu appearing, especially on slower machines or RDP sessions. Add a 0.5-second Wait action between the right-click and the subsequent menu interaction to avoid "element not found" errors.
For a deeper dive on handling transient UI elements like menus and dialogs, see Automating Windows Dialog Boxes and Pop-Up Windows in Power Automate Desktop: Handling Alerts, File Pickers, and Modal Prompts Reliably.
When UI automation approaches are unreliable — especially in unattended runs where the desktop session might be locked — PowerShell gives you a more direct path to tray icon information. The Windows Shell exposes tray icon data through COM interfaces.
Here's a PowerShell script that enumerates all visible tray icons and their tooltips without requiring any UI interaction:
# Enumerate system tray icons using Shell COM interface
$Shell = New-Object -ComObject Shell.Application
# Access the system tray
Add-Type @"
using System;
using System.Runtime.InteropServices;
using System.Text;
public class TrayInfo {
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(
IntPtr hwndParent, IntPtr hwndChildAfter,
string lpszClass, string lpszWindow);
[DllImport("user32.dll")]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
public static extern bool EnumChildWindows(
IntPtr hwndParent, EnumChildCallback lpEnumFunc, IntPtr lParam);
public delegate bool EnumChildCallback(IntPtr hwnd, IntPtr lParam);
}
"@
# Find the notification area toolbar
$taskbar = [TrayInfo]::FindWindow("Shell_TrayWnd", $null)
$trayNotify = [TrayInfo]::FindWindowEx($taskbar, [IntPtr]::Zero, "TrayNotifyWnd", $null)
$sysPager = [TrayInfo]::FindWindowEx($trayNotify, [IntPtr]::Zero, "SysPager", $null)
$toolbar = [TrayInfo]::FindWindowEx($sysPager, [IntPtr]::Zero, "ToolbarWindow32", $null)
$sb = New-Object System.Text.StringBuilder(256)
[TrayInfo]::GetWindowText($toolbar, $sb, 256)
Write-Output "Toolbar found: $($sb.ToString())"
# Use UI Automation .NET directly for cleaner access
Add-Type -AssemblyName UIAutomationClient
Add-Type -AssemblyName UIAutomationTypes
$automation = [System.Windows.Automation.AutomationElement]
$root = $automation::RootElement
$condition = New-Object System.Windows.Automation.PropertyCondition(
$automation::NameProperty, "Notification Area"
)
$notifArea = $root.FindFirst(
[System.Windows.Automation.TreeScope]::Descendants,
$condition
)
if ($notifArea -ne $null) {
$buttonCondition = New-Object System.Windows.Automation.PropertyCondition(
$automation::ControlTypeProperty,
[System.Windows.Automation.ControlType]::Button
)
$buttons = $notifArea.FindAll(
[System.Windows.Automation.TreeScope]::Children,
$buttonCondition
)
$results = @()
foreach ($button in $buttons) {
$name = $button.GetCurrentPropertyValue($automation::NameProperty)
$results += $name
}
$results -join "||"
} else {
Write-Output "NOTIFICATION_AREA_NOT_FOUND"
}
Capture the output and split on || in PAD to get a list of all current tray icon tooltips. You can then search that list for your target application:
Run PowerShell script: [script above]
Store output in: TrayIconsRaw
Split text: TrayIconsRaw
Delimiter: "||"
Store result in: TrayIconsList
FOR EACH icon IN TrayIconsList
IF icon CONTAINS "DataSync Agent" THEN
SET DataSyncIconText TO icon
EXIT LOOP
END IF
END FOR EACH
This is particularly valuable in unattended automation contexts. If you're running your flows without an active desktop session, see Attended vs Unattended RPA: Choosing a Run Mode and Configuring Machines in Power Automate for the full picture on session requirements.
Now let's put this together into a complete decision-making pattern. After you've captured the tray icon tooltip or notification text, you need to route your flow to the right path.
Here's a realistic scenario: the DataSync Agent tray icon can show five states. Each requires different downstream handling:
# Assume DataSyncIconText is populated from polling loop above
IF DataSyncIconText CONTAINS "Sync complete" THEN
# Happy path: process the synced data
RUN SUBFLOW: ProcessSyncedData
ELSE IF DataSyncIconText CONTAINS "Sync in progress" THEN
# Still running - not ready yet, extend the wait
SET SyncStatus TO "InProgress"
Wait 30 seconds
# Re-enter polling (or use a flag to continue the outer loop)
ELSE IF DataSyncIconText CONTAINS "Error" OR DataSyncIconText CONTAINS "Failed" THEN
# Extract the error message from the tooltip
# Tooltip format: "DataSync Agent - Error: Connection timeout (Code 1042)"
Split text: DataSyncIconText
Separator: "Error: "
Store in: ErrorParts
SET ErrorDetail TO ErrorParts[1] # "Connection timeout (Code 1042)"
RUN SUBFLOW: HandleSyncError
Input: ErrorDetail
ELSE IF DataSyncIconText CONTAINS "Paused" THEN
# Someone manually paused the agent - alert and stop
Send email notification
SET FlowResult TO "ManualIntervention"
EXIT FLOW
ELSE
# Unknown state - log and continue monitoring
Append to log file: "Unknown tray state: " + DataSyncIconText
END IF
Tip
Build your status parsing logic as a dedicated subflow that accepts the raw tooltip text and returns a standardized status code. This makes your main flow cleaner and lets you reuse the same parsing logic across multiple flows that interact with the same application. For more on this pattern, see Subflows and Reusable Logic in Power Automate Desktop.
Let's build a complete, working example. This exercise creates a flow that monitors a hypothetical data synchronization tool's tray icon, waits for sync completion, logs the outcome, and triggers downstream Excel processing.
Setup: For this exercise, you can simulate the target application by using any application that shows a tray icon — Slack, OneDrive, or even Windows Defender will work for practicing the UI element capture. Replace the selector references with your actual target application.
The flow has four parts:
# Set up tracking variables
SET FlowStartTime TO Current date and time
SET SyncStatus TO "Pending"
SET MaxWaitMinutes TO 10
SET PollIntervalSeconds TO 5
# Verify the sync agent is running before starting
Run PowerShell:
$proc = Get-Process "DataSyncAgent" -ErrorAction SilentlyContinue
if ($proc) { Write-Output "RUNNING" } else { Write-Output "NOT_RUNNING" }
Store in: AgentStatus
IF AgentStatus DOES NOT EQUAL "RUNNING" THEN
Log event: "DataSync Agent not running at flow start"
THROW ERROR "Agent process not found"
END IF
# Right-click tray icon and select "Start Sync Now"
Right-click UI element: TrayIcon_DataSyncAgent
Wait 1 second
Click UI element: MenuItem_StartSyncNow
# Record trigger time
SET SyncTriggerTime TO Current date and time
Log event: "Sync triggered at " + SyncTriggerTime
SET ElapsedSeconds TO 0
SET MaxSeconds TO MaxWaitMinutes * 60
LOOP
ON BLOCK ERROR
Log event: "Failed to read tray icon at elapsed " + ElapsedSeconds + "s"
SET TrayReadFailed TO True
ELSE
SET TrayReadFailed TO False
END
IF TrayReadFailed = False THEN
Get details of UI element: TrayIcon_DataSyncAgent
Attribute: Name
Store in: CurrentTooltip
IF CurrentTooltip CONTAINS "Sync complete" THEN
SET SyncStatus TO "Complete"
EXIT LOOP
END IF
IF CurrentTooltip CONTAINS "Error" OR CurrentTooltip CONTAINS "Failed" THEN
SET SyncStatus TO "Error"
SET SyncErrorDetail TO CurrentTooltip
EXIT LOOP
END IF
END IF
Wait PollIntervalSeconds seconds
SET ElapsedSeconds TO ElapsedSeconds + PollIntervalSeconds
IF ElapsedSeconds >= MaxSeconds THEN
SET SyncStatus TO "Timeout"
EXIT LOOP
END IF
END LOOP
IF SyncStatus = "Complete" THEN
# Open Excel and run the post-sync processing macro
Open Excel workbook: "C:\Reports\SyncProcessing.xlsx"
Run Excel macro: "ProcessNewSyncData"
Save and close workbook
Log event: "Sync completed and processed successfully"
ELSE IF SyncStatus = "Error" THEN
# Write error to tracking sheet
Open Excel workbook: "C:\Reports\SyncErrors.xlsx"
Write to cell: [next empty row, Col A] = FlowStartTime
Write to cell: [next empty row, Col B] = SyncErrorDetail
Save and close workbook
# Send alert email
Send email:
To: "ops-team@company.com"
Subject: "DataSync Agent Error - Action Required"
Body: "Sync failed with: " + SyncErrorDetail
ELSE IF SyncStatus = "Timeout" THEN
Send email:
To: "ops-team@company.com"
Subject: "DataSync Agent Timeout - Sync Did Not Complete"
Body: "Flow waited " + MaxWaitMinutes + " minutes without sync completion."
END IF
For the Excel interactions in Part 4, see Automating Excel with Power Automate Desktop: Reading, Writing, and Running Macros for the action specifics.
Root cause: The tray icon isn't visible (it's in the overflow), the application isn't running, or the element has moved because the icon order changed.
Fix: Add an explicit check for the overflow area before attempting to read the main tray. Use error handling to distinguish "application not running" (serious problem) from "icon in overflow" (solvable problem). Build your selector with Contains matching on the app name rather than exact text matching.
Root cause: Classic balloon tips have a very short display window, and if your flow is mid-action on another element, it will miss them.
Fix: Switch to the PowerShell-based notification history approach for any application that uses modern Windows notifications. For genuinely old Win32 balloon tips, the only reliable approach is a tight polling loop (0.25–0.5 second intervals) that's running before the notification is expected to appear. For production flows, consider using Extracting Text from PDFs, Images, and Scanned Documents with OCR in Power Automate Desktop as a fallback — OCR a screenshot the moment you detect the tooltips_class32 window.
Root cause: Unattended runs execute in a different Windows session, often with a locked or minimized desktop. The notification area toolbar may not be rendered or accessible in that session state.
Fix: First, verify that your unattended machine is configured to run with an interactive session where the tray is visible. See Attended vs Unattended RPA: Choosing a Run Mode and Configuring Machines in Power Automate for session configuration details. Second, use the PowerShell UI Automation approach from earlier — it's more robust in non-interactive sessions than PAD's native UI element actions.
Root cause: The notification listener permission hasn't been granted, or the notification platform service isn't running.
Fix: Run this check in your PowerShell script before querying notifications:
$listener = [Windows.UI.Notifications.Management.UserNotificationListener]::Current
$accessStatus = $listener.RequestAccessAsync().AsTask().Result
if ($accessStatus -ne [Windows.UI.Notifications.Management.UserNotificationListenerAccessStatus]::Allowed) {
Write-Output "ACCESS_DENIED: $accessStatus"
exit 1
}
If it returns ACCESS_DENIED, the permission needs to be granted manually in Windows Settings (Notifications & Actions) or via MDM policy before the flow can run.
Root cause: Context menu item positions can change based on application state (grayed out items shift the layout), and if you captured the selector for "Start Sync Now" when a sync was idle, the same menu might show "Stop Sync" in the same position when a sync is running.
Fix: Always select context menu items by their Name attribute (the menu item text), never by position. Check the item's enabled state before clicking:
Get details of UI element: MenuItem_StartSyncNow
Attribute: IsEnabled
Store in: MenuItemEnabled
IF MenuItemEnabled = True THEN
Click UI element: MenuItem_StartSyncNow
ELSE
Log event: "StartSyncNow menu item is disabled - sync may already be in progress"
END IF
Warning
Always close a context menu you've opened if you decide not to click anything. An open context menu will block other UI interactions. Use the Escape key action (Send keys: {Escape}) to dismiss it cleanly.
You now have a complete toolkit for working with the Windows notification area in Power Automate Desktop. The core skills to take away:
Contains matching to handle dynamic tooltip text.From here, consider extending this pattern to multi-application scenarios — tray monitoring is often just one trigger in a larger orchestration. If your flow needs to react to tray events and then transfer data between applications, Automating Multi-Application Workflows in Power Automate Desktop: Transferring Data Between Windows Apps, Web Browsers, and Excel in a Single Desktop Flow covers the broader orchestration patterns.
For production deployments of flows like this — where the tray monitoring needs to run reliably 24/7 without manual intervention — invest time in understanding your session management and machine configuration. The difference between a flow that works in your dev environment and one that holds up in production is almost always the session setup.