> For the complete documentation index, see [llms.txt](https://docs.sentiance.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sentiance.com/implementing-features/insights/lifestyle-insights.md).

# Lifestyle Insights

{% hint style="info" %}
To learn about the Lifestyle Insights feature, check out [this page](/getting-started/features-catalog/lifestyle-insights.md).

This feature is currently in **Early Access** and is still under active development
{% endhint %}

## Prerequisites

The Lifestyle Insights feature relies on additional library dependencies alongside the core SDK dependency. To start using this feature, you must first add these dependencies to you project.

<details>

<summary>iOS</summary>

This feature is included in the main SDK framework. No additional dependencies are needed.

</details>

<details>

<summary>Android</summary>

Open your app <mark style="color:$success;">**`build.gradle`**</mark> file and add the lifestyle dependency.

{% code title="app/build.gradle" %}

```kotlin
dependencies {
    implementation(platform('com.sentiance:sdk-bom:<sentiance-version>'))
    implementation("com.sentiance:sdk-lifestyle")
}
```

{% endcode %}

</details>

<details>

<summary>React Native</summary>

This feature is included after installing the following modules:

* [@sentiance-react-native/core](https://www.npmjs.com/package/@sentiance-react-native/core)
* [@sentiance-react-native/event-timeline](https://www.npmjs.com/package/@sentiance-react-native/event-timeline)
* [@sentiance-react-native/user-context](https://www.npmjs.com/package/@sentiance-react-native/user-context)

</details>

<details>

<summary>Flutter</summary>

This feature can be added by installing the following packages:

* [sentiance\_core](https://pub.dev/packages/sentiance_core)
* [sentiance\_event\_timeline](https://pub.dev/packages/sentiance_event_timeline)
* [sentiance\_user\_context](https://pub.dev/packages/sentiance_user_context)

</details>

## Utilize the User Context APIs

In this section, you can find examples of how to query the Sentiance SDK for the user's current context, and how to register to receive context updates in your app, as the user's context changes.

### Query for the User's Current Context

The user's context includes the following information:

* Recent transport and stationary events, with venue information if available.
* The user's last known location.
* The user's home and work locations, if detected.
* The user's current semantic time (e.g. morning time, lunch time).
* The user's segments, if detected (e.g. dog walker, aggressive driver).

The population of this context information happens offline, on the device.

{% tabs %}
{% tab title="iOS" %}

```swift
Sentiance.shared.requestUserContext { context, error in
    guard let context = context else {
        print("Error: \(error?.failureReason)")
        return
    }
    
    print("Recent events:")
    
    // Print the recent events
    context.events.forEach({ event in
        print("Event ID: \(event.eventId)")
        print("Started on: \(event.startDate)")
        print("Ended on: \(event.endDate)")
        
        if event.type == .inTransport {
            let transport =  event as! SENTTransportEvent
            
            print("Type: transport")
            print("Mode: \(toStringMode(transport.transportMode))")
            
            if let distance = transport.distanceInMeters {
                print("Distance: \(distance)")
            }
            
            print("Waypoints: \(transport.waypoints)")
            
        }
        else if event.type == .stationary {
            let stationary =  event as! SENTStationaryEvent
            
            print("Type: stationary")
            print("Location: \(stationary.location)")
            print("Venue: \(stationary.venue)")
        }
        else if event.type == .offTheGrid {
            print("Type: off-the-grid")
        }
        else {
            print("Type: unknown")
        }
        
        print("")
    })
    
    // Print the home & work locations, semantic time, and last known location
    print("Home venue: \(context.home)")
    print("Work venue: \(context.work)")
    print("Semantic time: \(toString(context.semanticTime))")
    print("Last known location: \(context.lastKnownLocation)")
    
    // Print the user's active segments
    print("Active segments:")
    
    context.activeSegments.forEach { segment in
        print("  Category: \(toString(segment.category))")
        print("  Subcategory: \(toString(segment.subcategory))")
        print("  Type: \(toString(segment.type))")
        print("  Start date: \(toString(segment.startDate))")
        print("  End date: \(toString(segment.endDate))")
        
        print("  Attributes: ")
        segment.attributes.forEach { attribute in
            print("    \(attribute.name): \(attribute.value)")
        }
    }
}
```

{% endtab %}

{% tab title="Android" %}

```kotlin
UserContextApi.getInstance(context).requestUserContext()
    .addOnFailureListener { error ->
        print ("User context retrieval failed with reason ${error.reason}")
    }
    .addOnSuccessListener { context ->

        // Print the recent events
        print("Recent events:")

        context.events.forEach { event ->
            print("Event ID: ${event.id}")
            print("Started on: ${event.startTime}")
            print("Ended on: ${event.endTime}")

            when (event.eventType) {
                EventType.IN_TRANSPORT -> {
                    val transport = event as TransportEvent!

                    print("Type: transport")
                    print("Mode: ${transport.transportMode}")

                    if (transport.distanceInMeters != null) {
                        print("Distance: ${transport.distanceInMeters}")
                    }

                    print("Waypoints: ${transport.waypoints}")
                }
                EventType.STATIONARY -> {
                    val stationary = event as StationaryEvent!

                    print("Type: stationary")
                    print("Location: ${stationary.location}")
                    print("Venue: ${stationary.venue}")
                }
                EventType.OFF_THE_GRID -> {
                    print("Type: off-the-grid")
                }
                else -> {
                    print("Type: unknown")
                }
            }
        }

        // Print the home & work locations, semantic time, and last known location
        print("Home venue: ${context.home}")
        print("Work venue: ${context.work}")
        print("Semantic time: ${context.semanticTime}")
        print("Last known location: ${context.lastKnownLocation}")

        // Print the user's active segments
        print("Active segments:")

        context.activeSegments.forEach { segment ->
            print("  Category: ${segment.category}")
            print("  Subcategory: ${segment.subcategory}")
            print("  Type: ${segment.type}")
            print("  Start date: ${segment.startTime}")
            print("  End date: ${segment.endTime}")

            print("  Attributes: ")
            segment.attributes.forEach { attribute ->
                print("    ${attribute.name}: ${attribute.value}")
            }
        }
    }
```

{% endtab %}

{% tab title="React Native" %}

```javascript
import SentianceUserContext from '@sentiance-react-native/user-context';

const context = await SentianceUserContext.requestUserContext();

// Print the recent events
for (const event of context.events) {
    console.log(`Event ID: ${event.id}`);
    console.log(`Started on: ${event.startTime}`);
    console.log(`Ended on: ${event.endTime}`);

    switch (event.type) {
        case 'IN_TRANSPORT':
            const transport = event;
            console.log('Type: transport');
            console.log(`Mode: ${transport.transportMode}`);

            if (transport.distance) {
                console.log(`Distance: ${transport.distance}`);
            }
            console.log(`Waypoints: ${JSON.stringify(transport.waypoints)}`);
            break;
        case 'STATIONARY':
            const stationary = event;
            console.log('Type: stationary');
            console.log(`Location: ${JSON.stringify(stationary.location)}`);
            console.log(`Venue: ${JSON.stringify(stationary.venue)}`);
            break;
        case 'OFF_THE_GRID':
            console.log('Type: off-the-grid');
            break;
        default:
            console.log('Type: unknown');
    }
}

// Print the home & work locations, semantic time, and last known location
console.log(`Home venue: ${JSON.stringify(context.home)}`)
console.log(`Work venue: ${JSON.stringify(context.work)}`)
console.log(`Semantic time: ${context.semanticTime}`)
console.log(`Last known location: ${JSON.stringify(context.lastKnownLocation)}`)

// Print the user's active segments
console.log('Active segments:')

for (const segment of context.activeSegments) {
    console.log(`  ID: ${segment.id}`)
    console.log(`  Category: ${segment.category}`)
    console.log(`  Subcategory: ${segment.subcategory}`)
    console.log(`  Type: ${segment.type}`)
    console.log(`  Start date: ${segment.startTime}`)
    console.log(`  End date: ${segment.endTime}`)

    console.log('  Attributes:')
    segment.attributes.forEach { attribute ->
        console.log(`    ${attribute.name}: ${attribute.value}`)
    }
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:sentiance_user_context/sentiance_user_context.dart';
import 'package:sentiance_event_timeline/sentiance_event_timeline.dart';

final sentianceUserContext = SentianceUserContext();

void fetchUserContext() async {
  final context = await sentianceUserContext.requestUserContext();

  // Print the recent events
  for (final event in context.events) {
    print('Event ID: ${event.id}');
    print('Started on: ${event.startTimeMs}');
    print('Ended on: ${event.endTimeMs}');

    if (event is TransportEvent) {
      final transport = event;
      print('Type: transport');
      print('Mode: ${transport.transportMode}');
      print('Distance: ${transport.distance}');
      print('Waypoints: ${transport.waypoints}');
    } else if (event is StationaryEvent) {
      print('Type: stationary');
      print('Location: ${event.location}');
      print('Venue: ${event.venue}');
    } else if (event is OffTheGridEvent) {
      print('Type: off-the-grid');
    } else if (event is UnknownEvent) {
      print('Type: unknown');
    }
  }

  // Print the home & work locations, semantic time, and last known location
  print('Home venue: ${context.home}');
  print('Work venue: ${context.work}');
  print('Semantic time: ${context.semanticTime}');
  print('Last known location: ${context.lastKnownLocation}');

  // Print the user's active segments
  print('Active segments:');

  for (final segment in context.activeSegments) {
    print('  ID: ${segment.segmentId}');
    print('  Category: ${segment.category}');
    print('  Subcategory: ${segment.subcategory}');
    print('  Type: ${segment.type}');
    print('  Start date: ${segment.startTimeMs}');
    print('  End date: ${segment.endTimeMs}');

    print('  Attributes:');
    for (final attribute in segment.attributes.nonNulls) {
      print('    ${attribute.name}: ${attribute.value}');
    }
  }
}
```

{% endtab %}
{% endtabs %}

### Subscribe for User Context Updates

{% hint style="info" %}
Checkout [Real-time Listeners](/sdk/appendix/real-time-listeners.md) to read more about implementing the SDK's Listeners
{% endhint %}

You can subscribe to receive updates, as the user's current context changes.&#x20;

{% tabs %}
{% tab title="iOS" %}
{% code lineNumbers="true" %}

```swift
public class UserContextHandler: SENTUserContextDelegate {
    
    public func subscribe() {
        Sentiance.shared.userContextDelegate = self
    }    
        
    public func didUpdate(_ userContext: SENTUserContext, 
       forCriteriaMask criteriaMask: SENTUserContextUpdateCriteria) {
        
        // Check the updated criteria
        if criteriaMask.contains(.currentEvent) {
            print("The user's current event was updated")
        }
        if criteriaMask.contains(.visitedVenues) {
            print("The user's visited venue information was updated")
        }
        if criteriaMask.contains(.activeSegments) {
            print("The user's active segments were updated")
        }
       
        // Handle the updated context data (see the Query for the 
        // User's Current Context example above)
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Android" %}

```kotlin
UserContextApi.getInstance(context)
  .addUserContextUpdateListener { criteria, context ->
    // Check the updated criteria
    if (criteria.contains(UserContextUpdateCriteria.CURRENT_EVENT)) {
        print("The user's current event was updated")
    }
    if (criteria.contains(UserContextUpdateCriteria.VISITED_VENUES)) {
        print("The user's visited venue information was updated")
    }
    if (criteria.contains(UserContextUpdateCriteria.ACTIVE_SEGMENTS)) {
        print("The user's active segments were updated")
    }

    // Handle the updated context data (see the Query for the
    // User's Current Context example above)
}
```

{% endtab %}

{% tab title="React Native" %}
To get user context updates even when your app is in the background, place the following code inside your app's entrypoint **index.js** file. If you're only interested in these updates when your app is foregrounded, place this code inside the appropriate UI code instead.

```javascript
import {addUserContextUpdateListener} from "@sentiance-react-native/user-context";
import SentianceCore from "@sentiance-react-native/core";

await SentianceCore.ensureInitialized(); // Ensure SDK is initialized

// If you're subscribing to event updates only in the foreground, make sure
// to call subscription.remove() inside your component's componentWillUnmount() function
const subscription = addUserContextUpdateListener(userContext => {
    // Handle the updated context data (see the Query for the
    // User's Current Context example above)
});
```

{% endtab %}

{% tab title="Flutter" %}
Create a **background.dart** file under your project's **lib** folder with the following code:

{% code title="background.dart" %}

```dart
import 'package:sentiance_user_context/sentiance_user_context.dart';
import 'package:sentiance_core/sentiance_core.dart';

@pragma('vm:entry-point')
void registerUserContextListener() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SentianceCore.ensureInitialized();

  SentianceUserContext.registerUserContextUpdateListener((criteria, context) {
    // Check the updated criteria
    if (criteria.contains(UserContextUpdateCriteria.currentEvent)) {
      print("The user's current event was updated");
    }
    if (criteria.contains(UserContextUpdateCriteria.visitedVenues)) {
      print("The user's visited venue information was updated");
    }
    if (criteria.contains(UserContextUpdateCriteria.activeSegments)) {
      print("The user's active segments were updated");
    }

    // Handle the updated context data (see the Query for the
    // User's Current Context example above)
  });
}
```

{% endcode %}

Add the following code, depending on your target platform.

For **iOS**, add the following to your app delegate class:

{% code title="AppDelegate.swift" %}

```swift
import Flutter
import sentiance_user_context

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {

    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
    
        // Other code
        
        // Make sure the SDK is initialized before calling this
        SentianceUserContextPlugin.initializeListener(
            withEntryPoint: "registerUserContextListener",
            libraryURI: "package:your_app_package_name/background.dart"
        )
        
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}
```

{% endcode %}

For **Android**, add this code to your custom application class:

{% code title="MainApplication.kt" %}

```kotlin
import android.app.Application
import com.sentiance.user_context_plugin.UserContextPlugin

class MainApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        
        // Other code

        val dartLibrary = "package:your_app_package_name/background.dart"
        // Make sure the SDK is initialized before calling this
        UserContextPlugin.initializeListener(this, dartLibrary, "registerUserContextListener")
    }
}
```

{% endcode %}

{% hint style="info" %}
If you're calling other 3rd party plugin APIs inside your `registerUserContextListener` Dart function, then you need to register these plugins with the Sentiance SDK. See [this](/sdk/appendix/flutter/declaring-3rd-party-plugins.md) for more details.
{% endhint %}
{% endtab %}
{% endtabs %}
