diff --git a/docs/tutorials/building-a-geofence-powered-live-activity.mdx b/docs/tutorials/building-a-geofence-powered-live-activity.mdx
new file mode 100644
index 000000000..fb70b7ca8
--- /dev/null
+++ b/docs/tutorials/building-a-geofence-powered-live-activity.mdx
@@ -0,0 +1,163 @@
+---
+sidebar_position: 7
+title: Building a geofencing powered live activity
+---
+
+In this tutorial, we show you how to use the Radar [flutter SDK](/sdk/flutter) and [geofences](/geofences) to show a live activity when a user enters a geofence.
+
+In this example, we show live activities on iOS using [event listeners](/sdk/flutter#background-tracking).
+
+## Languages used
+
+- Flutter
+- Swift
+
+## Features used
+
+- [Flutter SDK](/sdk/flutter)
+- [Geofences](/geofences)
+
+## Steps
+
+### Step 1: Sign up for Radar
+
+If you haven't already, sign up for Radar to get your API key. You can create up to 1,000 geofences and make up to 100,000 API requests per month for free.
+
+Get API keys
+
+### Step 2: Import geofences
+
+On the [Geofences page](https://radar.com/dashboard/geofences), create a geofence. It may be useful to assign a specific tag to geofences you hope to power live activities with.
+
+### Step 3: Implement live activities
+
+Implement live activities using the [flutter_live_activities](https://github.com/istornz/flutter_live_activities) library. Their README page contains instructions to set up the widget extension, necessary permissions and the iOS app group. You can also use their [example app](https://github.com/istornz/flutter_live_activities/tree/main/example) for reference.
+
+### Step 4: Install the Radar flutter SDK
+
+Follow the installation [instructions](/sdk/flutter#ios) to add `flutter_radar` to your project.
+
+Initialize the SDK in your a class that is initialized near the root of the flutter app with your publishable API key.
+
+Also implement the boiler plate setup code for `flutter_live_activities`
+
+Then, [request location permissions](/sdk/flutter#request-permissions) and start tracking:
+
+```dart
+import 'package:flutter_radar/flutter_radar.dart';
+import 'package:live_activities/live_activities.dart';
+...
+
+class Home extends StatefulWidget {
+ const Home({super.key});
+
+ @override
+ State createState() => _HomeState();
+}
+
+
+class _HomeState extends State {
+ final _liveActivitiesPlugin = LiveActivities();
+
+ @override
+ void initState() {
+ super.initState();
+ initRadar();
+
+ _liveActivitiesPlugin.init(appGroupId: 'YOUR_APP_GROUP_ID');
+ ...
+ }
+
+ Future initRadar() async {
+ Radar.initialize('prj_test_pk_...');
+ Radar.setUserId('YOUR_USER_NAME');
+ Radar.setDescription('YOUR_USER_DESCRIPTION');
+
+ // optionally implement your own location permissions request flow
+ await Radar.requestPermissions(false);
+ await Radar.requestPermissions(true);
+ var permissionStatus = await Radar.getPermissionsStatus();
+ if (permissionStatus != "DENIED") {
+ Radar.startTracking('responsive');
+ }
+
+ }
+}
+
+
+```
+
+### Step 5: Listen for events
+
+Implement `onEvents` to listen for geofence entry events to control live activities:
+
+```dart
+class _HomeState extends State {
+ ...
+ @override
+ void initState() {
+ super.initState();
+ initRadar();
+ ...
+ }
+
+ @pragma('vm:entry-point')
+ void onEvents(Map res) async {
+ if (res.containsKey('events')) {
+ List events = res['events'];
+ for (var event in events) {
+ // start the live activity when we enter the geofence
+ if (event['type'] == 'user.entered_geofence' && event['geofence']['tag'] == 'YOUR_TAG_FOR_LIVE_ACTIVITY') {
+ if (_latestActivityId == null) {
+ // Start a live activity when user enters geofence
+ final activityId = await _liveActivitiesPlugin.createActivity({
+ 'geofenceName': event['geofence']['description'] ?? 'Unknown geofence',
+ 'enteredAt': DateTime.now().toIso8601String(),
+ });
+ setState(() => _latestActivityId = activityId);
+ } else {
+ _liveActivitiesPlugin.updateActivity(
+ _latestActivityId!,
+ {
+ 'geofenceName': event['geofence']['description'] ?? 'Unknown geofence',
+ 'enteredAt': DateTime.now().toIso8601String(),
+ }
+ );
+ }
+
+ }
+ if (event['type'] == 'user.exited_geofence' && event['geofence']['tag'] == 'YOUR_TAG_FOR_LIVE_ACTIVITY') {
+ _liveActivitiesPlugin.endAllActivities();
+ setState(() => _latestActivityId = null);
+ }
+ }
+ }
+ }
+
+ Future initRadar() async {
+ Radar.initialize('prj_test_pk_...');
+ ...
+ Radar.onEvents(onEvents);
+
+ }
+}
+```
+
+### Step 6: Access geofence information from the live activity widget
+
+Access the values inside the widget using the shared user defaults.
+
+```swift
+let geofenceDescription = sharedDefault.string(forKey: context.attributes.prefixedKey("geofenceName"))!
+let enteredAt = = sharedDefault.string(forKey: context.attributes.prefixedKey("enteredAt"))!
+
+```
+There are may resources that you can reference for implementing the live activity UI, here are some tutorials:
+- https://canopas.com/integrating-live-activity-and-dynamic-island-in-i-os-a-complete-guide
+- https://medium.com/kinandcartacreated/how-to-build-ios-live-activity-d1b2f238819e
+
+
+
+## Support
+
+Have questions or feedback on this documentation? Let us know! Contact us at [radar.com/support](https://radar.com/support).
diff --git a/sidebars.js b/sidebars.js
index 278233c53..6a27b06b9 100644
--- a/sidebars.js
+++ b/sidebars.js
@@ -106,6 +106,7 @@ module.exports = {
"tutorials/displaying-radar-maps-with-react-native",
"tutorials/displaying-radar-maps-with-flutter",
"tutorials/create-a-custom-map-style",
+ "tutorials/building-a-geofence-powered-live-activity",
],
},
"waypoint",