Edit

Set up a geofence

A Geofence defines a circular geographic boundary around a point of interest. Your app receives notifications when the user enters or exits the boundary. Geofences are useful for location-based reminders, alerts, check-ins, and contextual content delivery.

This article shows how to create a geofence, monitor state changes, and handle geofence events in a Windows App SDK (WinUI 3) app.

Prerequisites

  • A WinUI 3 project created from the Blank App, Packaged (WinUI 3 in Desktop) template.
  • The Location capability declared in the package manifest. See Get the user's location for instructions.

Request location access

Call Geolocator.RequestAccessAsync before creating or monitoring geofences.

using Windows.Devices.Geolocation;
using Windows.Devices.Geolocation.Geofencing;

var accessStatus = await Geolocator.RequestAccessAsync();
if (accessStatus != GeolocationAccessStatus.Allowed)
{
    StatusText.Text = "Location access is required for geofencing.";
    return;
}

Create a geofence

Define a geofence by specifying an identifier, a geographic center, a radius in meters, and which state transitions to monitor (entered, exited, or removed).

var position = new BasicGeoposition
{
    Latitude = 47.6062,
    Longitude = -122.3321
};

var geocircle = new Geocircle(position, 200); // 200-meter radius

var geofence = new Geofence(
    "SeattleDowntown",                          // Unique identifier
    geocircle,                                  // Geographic boundary
    MonitoredGeofenceStates.Entered |           // States to monitor
    MonitoredGeofenceStates.Exited,
    false,                                      // Single use: false = persistent
    TimeSpan.FromSeconds(10)                    // Dwell time before triggering
);

GeofenceMonitor.Current.Geofences.Add(geofence);

Geofence parameters

Parameter Description
id A unique string that identifies the geofence. Use this to distinguish events from different geofences.
geoshape A Geocircle that defines the boundary. Only circular boundaries are supported.
monitoredStates Which transitions to monitor: Entered, Exited, or Removed. Combine with the | operator.
singleUse If true, the geofence triggers once and is removed automatically.
dwellTime How long the user must remain inside (or outside) the boundary before the event fires. Helps filter out brief crossings.

Monitor geofence events in the foreground

Subscribe to the GeofenceMonitor.Current.GeofenceStateChanged event to receive notifications while your app is running.

GeofenceMonitor.Current.GeofenceStateChanged += OnGeofenceStateChanged;

Read the reports and update the UI. The event fires on a background thread, so use DispatcherQueue to marshal UI updates.

private void OnGeofenceStateChanged(GeofenceMonitor sender, object args)
{
    var reports = sender.ReadReports();

    DispatcherQueue.TryEnqueue(() =>
    {
        foreach (var report in reports)
        {
            var state = report.NewState;
            var id = report.Geofence.Id;

            switch (state)
            {
                case GeofenceState.Entered:
                    StatusText.Text = $"Entered geofence: {id}";
                    break;
                case GeofenceState.Exited:
                    StatusText.Text = $"Exited geofence: {id}";
                    break;
                case GeofenceState.Removed:
                    StatusText.Text = $"Geofence removed: {id}";
                    // Re-add the geofence if it was removed due to expiration
                    break;
            }
        }
    });
}

Monitor geofence status changes

Use GeofenceMonitor.Current.StatusChanged to detect when geofence monitoring is disabled — for example, when the user turns off location services.

GeofenceMonitor.Current.StatusChanged += (sender, args) =>
{
    DispatcherQueue.TryEnqueue(() =>
    {
        var status = sender.Status;
        if (status == GeofenceMonitorStatus.Disabled)
        {
            StatusText.Text = "Geofence monitoring is disabled. Check location settings.";
        }
    });
};

Tip

When using geofences, monitor permission changes through GeofenceMonitor.StatusChanged rather than Geolocator.StatusChanged. A GeofenceMonitorStatus value of Disabled is equivalent to a PositionStatus of Disabled, but GeofenceMonitorStatus provides more context for geofencing scenarios.

Remove a geofence

Remove a geofence by finding it in the GeofenceMonitor.Current.Geofences collection.

var geofences = GeofenceMonitor.Current.Geofences;
var target = geofences.FirstOrDefault(g => g.Id == "SeattleDowntown");

if (target != null)
{
    geofences.Remove(target);
}

Best practices

  • Set a reasonable dwell time. A dwell time of at least 10 seconds helps filter out GPS jitter and prevents false triggers at boundary edges.
  • Use a radius of at least 50 meters. GPS accuracy varies by device and environment. A radius smaller than 50 meters may produce unreliable results.
  • Check internet access if needed. If your app performs network operations when a geofence event fires (such as sending a notification to a server), verify connectivity before creating the geofence.
  • Handle the Removed state. Geofences can be removed by the system if they expire or if the system is under resource pressure. Check for GeofenceState.Removed and re-create the geofence if your scenario requires it.
  • Don't monitor foreground and background simultaneously for the same geofence unless necessary. If you do, unregister the foreground listener when the app is suspended and re-register when it resumes.