Back to articles

My Public IP Address: my public IP next to the Windows clock

My Public IP Address: my public IP next to the Windows clock

"Can you send me your public IP so I can add it to the firewall?"

If you work for clients, you have heard that sentence. And you have opened a browser, typed "what is my ip", closed three cookie banners and copied the address from between the ads.

I hear it a lot. And I have one more problem: depending on the client, I am connected to a different VPN. This one sends all the traffic through the tunnel, that one only part of it, a third one drops on its own after the laptop goes to sleep. So the question is not only "what is my IP?", but also "which IP am I going out from, right now?".

I already had a small app for that on the Microsoft Store, My Public IP Address. It had aged. I rewrote it from scratch, a little for the need, a lot for the fun. It is free on the Store and the code is on GitHub.

TL;DR

  • Your public IP sits next to the clock: hover the icon to see it, click to copy it.
  • A notification shows up as soon as it changes: VPN dropping, new network, new address from your provider.
  • A history of your recent addresses, to know when it moved.
  • WinUI 3 and .NET 10, with all the logic in a library that does not depend on Windows, so it is tested.
  • No account, no ads, no tracking: the history stays on your PC.

What the app does

Nothing complicated, on purpose. It lives in the notification area, next to the clock.

Hover the icon: the tooltip gives the IPv4 and the IPv6.

Tooltip of the notification area icon: public IPv4 and IPv6

Click it: a small Windows 11 style panel opens above the clock, with the public IP, the local network address, a copy button for each, and the recent addresses.

Panel above the clock: public IPv4 and IPv6, local network and recent addresses

The screenshots use addresses reserved for documentation, not mine.

And above all, when the address changes, Windows tells me, with the old one and the new one:

Windows notification: "Your public IP address changed", with a button to copy the new address

That notification is what makes the difference with several VPNs. The tunnel drops without a word? I know right away, instead of spending ten minutes wondering why the client's server stopped answering.

Right-click gives the rest: copy, refresh, start with Windows, turn notifications off, quit.

Right-click menu: show, copy the IPv4 or the IPv6, refresh, start with Windows, notifications, quit

A few details that kept me busy

Showing an IP takes three lines of code. Making it reliable is another story. Here is what I learned on the way.

Never show an error as if it were an address

The app asks public services that just answer the IP as plain text: ipify, icanhazip, and checkip.amazonaws.com as a fallback. If one is down, it moves on to the next.

The trap is reading the answer. IPAddress.TryParse is very lenient: it accepts "1" or "10.1" and turns them into valid addresses. One odd error page, and I would copy a fake IP and give it to a client. So parsing is strict:

internal static bool TryParse(string text, AddressFamily family, out IPAddress? address)
{
	address = null;
	string candidate = text.Trim();

	if (family == AddressFamily.InterNetwork && candidate.Count(c => c == '.') != 3)
	{
		return false;
	}

	if (!IPAddress.TryParse(candidate, out IPAddress? parsed) || parsed.AddressFamily != family)
	{
		return false;
	}

	address = parsed;
	return true;
}

Following network changes

When you turn a VPN on, Windows reports a network change... then another one, then another, while the adapters settle. The app waits two seconds for things to calm down before asking for the address again. On top of that, it checks every 15 minutes, and retries more and more slowly after a failure (3 s, 5 s, 10 s, 30 s, then one minute).

Another detail: HttpClient keeps its connections open. After a VPN switch, it could reuse a connection from the old network. Short lifetimes fix that:

var handler = new SocketsHttpHandler
{
	ConnectTimeout = TimeSpan.FromSeconds(4),
	// Short lifetimes so that a network switch (VPN, Wi-Fi...) never reuses a stale connection
	PooledConnectionLifetime = TimeSpan.FromMinutes(1),
	PooledConnectionIdleTimeout = TimeSpan.FromSeconds(20),
};

IPv6 changes all the time, without it being a change

First tests with IPv6: one notification a day, for no reason. Windows uses "privacy extensions": the second half of the IPv6 address changes regularly, so that you cannot be tracked. The network itself does not change.

So for IPv6, I only compare the /64 prefix, the part that identifies the network:

internal static bool IsSameConnection(IpHistoryEntry a, IpHistoryEntry b) =>
	a.IPv4 == b.IPv4 && IPv6Prefix(a.IPv6) == IPv6Prefix(b.IPv6);

No notification for the first result of a session either: if the router got a new address overnight, I do not need to be told every time I log in.

The icon that vanished after an update

I did not see that one coming. Windows ties the identifier (a GUID) of a notification area icon to the path of the executable. But a Store app is installed in a folder that contains its version number. Update, new path, GUID rejected... and no more icon.

The fix fits in two lines: derive the GUID from the path.

string path = (Environment.ProcessPath ?? "MyPublicIp").ToUpperInvariant();
return new Guid(MD5.HashData(Encoding.UTF8.GetBytes(path)));

Under the hood

  • WinUI 3 and .NET 10, packaged as MSIX for the Store (x86, x64 and ARM64).
  • All the logic (IP lookup, refresh, history, change detection, panel placement) lives in MyPublicIp.Core, a library with no Windows dependency at all. The WinUI app is only a thin shell around it.
  • Direct consequence: everything is tested with xUnit. Time is injected with TimeProvider, so the refresh tests move a fake clock forward instead of waiting.
  • MVVM with CommunityToolkit.Mvvm: the panel and the menu share the same view model.
  • Self-contained, fully trimmed .NET runtime: about 8 MB per architecture instead of 60.
  • Starts with Windows through the MSIX startup task, which can be turned off from the app or from Windows Settings.

Privacy is simple: the app sends one HTTPS request to a "what is my IP" service, and that is all. No account, no analytics, no ads. The history (20 addresses at most) stays on your PC.

What I take away

  • Small tools are the best playgrounds. The need is clear, the scope fits in your head, and you can polish every detail.
  • A reliable app is mostly about the odd cases. Services going down, networks changing in bursts, IPv6 moving on its own.
  • Separating the logic from the UI always pays off. With a Core that knows nothing about Windows, I could test everything without ever starting the app.

If you also juggle several VPNs, or if people often ask for your IP, the app is on the Microsoft Store. The code is on GitHub, under the MIT license. Ideas and feedback are welcome in the issues.

Comments (0)

No comments yet. Be the first to comment!

Leave a comment

Your email will not be published.
An unhandled error has occurred. Reload 🗙

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please reload the page.