# Session Tracking in Mobile SDKs


This guide covers the session tracking feature available in the RudderStack [Android (Kotlin)]({{< ref "sources/event-streams/sdks/kotlin-sdk/" >}}) and [iOS (Swift)]({{< ref "sources/event-streams/sdks/swift-sdk/" >}}) SDKs.

## Overview

A session is a group of user interactions with your mobile application taking place within a given timeframe. For example, a single session can contain multiple screen views, events, social interactions, and ecommerce transactions.

Tracking user sessions helps you gather insights into the user journey and analyze their behaviour in detail.

The Android (Kotlin) and iOS (Swift) SDKs support two types of session tracking - [Automatic](#automatic-session-tracking) and [Manual](#manual-session-tracking).

## Automatic session tracking

By default, RudderStack tracks user sessions automatically and attaches the session information to each event fired using the mobile SDKs.

When you fire an event from the SDK, RudderStack automatically attaches the `sessionId` field to the event’s `context`. It is then persisted by the SDK, so the same session ID is attached to all the events of the same session, even if the app is restarted.

### Session start and end

An automatic session starts in the following scenarios:

- After the previous user session has ended, or 
- No session data is present in the storage.

An automatic session ends when [`sessionTimoutInMillis`](#session-configuration-parameters) amount of time has elapsed after the app is backgrounded or closed. This timeout is measured from the last app background/closed time to the app foreground/launch time.

### Manage automatic session

As mentioned above, RudderStack enables automatic session tracking by default. To turn off this feature, set `automaticSessionTracking` in the `sessionConfiguration` parameter within `Configuration` to `false` while initializing the SDK, as shown:

{{< tabs tabTotal="2" >}}
{{% tab tabName="Android (Kotlin)" %}}
```kotlin
analytics = Analytics(configuration = Configuration(
    writeKey = BuildConfig.WRITE_KEY,
    application = application,
    dataPlaneUrl = BuildConfig.DATA_PLANE_URL,
    sessionConfiguration = SessionConfiguration(
        automaticSessionTracking = false,   // Disables automatic session tracking
    )
))
```

The corresponding Java snippet is shown below:

```java
SessionConfiguration sessionConfiguration = new SessionConfigurationBuilder()
    .setAutomaticSessionTracking(false)   // Disables automatic session tracking
    .build();
Configuration configuration = new ConfigurationBuilder(application, writeKey, dataPlaneUrl)
    .setSessionConfiguration(sessionConfiguration)
    .build();
JavaAnalytics javaAnalytics = new JavaAnalytics(configuration);
```
{{% /tab %}}
{{% tab tabName="iOS (Swift)" %}}
```swift
analytics = Analytics(configuration: Configuration(
    writeKey: "<WRITE_KEY>",
    dataPlaneUrl: "<DATA_PLANE_URL>",
    sessionConfiguration: SessionConfiguration(
        automaticSessionTracking: false,   // Set this to "false" to disable automatic session tracking
    )
))
```

The corresponding Objective-C snippet is shown below:

```objectivec
RSSSessionConfigurationBuilder *sessionBuilder = [RSSSessionConfigurationBuilder new];
[sessionBuilder setAutomaticSessionTracking:NO];   // Set this to "NO" to disable automatic session tracking

RSSConfigurationBuilder *builder = [[RSSConfigurationBuilder alloc]
    initWithWriteKey:@"<WRITE_KEY>"
    dataPlaneUrl:@"<DATA_PLANE_URL>"];
[builder setSessionConfiguration:[sessionBuilder build]];

analytics = [[RSSAnalytics alloc] initWithConfiguration:[builder build]];
```
{{% /tab %}}
{{< /tabs >}}

### Configuration parameters

The `SessionConfiguration` class provides the following parameters to customize session management:

| Parameter | Type | <div style="width: 300px;">Description</div> | 
| :----------| :------------| :-------------| 
| `automaticSessionTracking` | Boolean / Bool | Enables automatic session tracking. <br /><br /> **Default value:** `true` |
| `sessionTimeoutInMillis` | Long / UInt64 | Sets the timeout duration for automatic session tracking in milliseconds. It is the time between the app closed or backgrounded to being foregrounded or relaunched again. <br /><br />The SDK times out a session and starts a new session after this time has elapsed. <br /><br />**Default value:** `300000` (5 minutes) |
| `updateSessionOnBackgroundEvents` | Boolean / Bool | When `false`, background events do not extend the session lifetime. Sessions expire based on foreground user interactions only. <br /><br />Set to `true` to allow background events to extend the session lifetime (restores the behavior prior to Android (Kotlin) SDK 1.7.0 and iOS (Swift) SDK 1.3.0). <br /><br />**Default value:** `false` |

### Sample event

A sample event payload with the session information attached is shown below:

```json
{
  "anonymousId": "19fb9683-3afe-48c5-84de-a22ac572b612",
  "channel": "mobile",
  "context": {
    "sessionId": 1740463597,
    "sessionStart": true,
    "traits": {
      "anonymousId": "19fb9683-3afe-48c5-84de-a22ac572b612"
    }
  },
  "event": "Application Opened",
  // Additional fields
  "messageId": "1b5f74c1-d324-42f2-a70b-95cbe4256614",
  "originalTimestamp": "2025-02-25T06:06:37.761Z",
  "properties": {
    "from_background": false,
    "version": "0.1.0"
  },
  "receivedAt": "2025-02-25T06:06:41.749Z",
  "rudderId": "e2c579a6-5820-459a-8100-0af86cf442a0",
  "sentAt": "2025-02-25T06:06:39.185Z",
  "type": "track"
}
```

{{< info >}}
The `sessionStart` field is present only in the first event since the start of a new session.
{{< /info >}}

### Flow diagrams

The below flow diagrams explain the automatic session workflows when the user either launches or foregrounds the app.

{{< details "**App launched**" >}}
<br/>

{{< figure src="images/event-stream-sources/mobile-sdks/automatic-session-tracking-app-launched.webp" alt="Automatic session tracking workflow for App Launched" >}}

{{< /details >}}

{{< details "**App foregrounded**" >}}
<br/>

{{< figure src="images/event-stream-sources/mobile-sdks/automatic-session-tracking-app-foregrounded.webp" alt="Automatic session tracking workflow for App Foregrounded" >}}

{{< /details >}}

## Manual session tracking

A manual session is fully managed by the user, that is, the user is responsible for the session start and end and there is **no** concept of timeout. This feature also lets you provide a custom `sessionId` for the manual session.

### Set up a manual session

To set up a manual session: 

1. Configure `automaticSessionTracking` to `false` while initializing the SDK — this disables automatic session tracking. 
2. Use the `startSession` API to start a new manual session.

{{< tabs tabTotal="2" >}}
{{% tab tabName="Android (Kotlin)" %}}
```kotlin
analytics = Analytics(configuration = Configuration(
    writeKey = BuildConfig.WRITE_KEY,
    application = application,
    dataPlaneUrl = BuildConfig.DATA_PLANE_URL,
    sessionConfiguration = SessionConfiguration(
        automaticSessionTracking = false,    // Disables automatic session tracking
    ),
))
```

The corresponding Java snippet is shown below:

```java
SessionConfiguration sessionConfiguration = new SessionConfigurationBuilder()
        .setAutomaticSessionTracking(false)    // Disables automatic session tracking
        .build();

Configuration configuration = new ConfigurationBuilder(application, writeKey, dataPlaneUrl)
        .setSessionConfiguration(sessionConfiguration)
        .build();

JavaAnalytics javaAnalytics = new JavaAnalytics(configuration);
```
{{% /tab %}}
{{% tab tabName="iOS (Swift)" %}}
```swift
let config = Configuration(
    writeKey: writeKey,
    dataPlaneUrl: dataPlaneUrl,
    sessionConfiguration: SessionConfiguration(
        automaticSessionTracking: false,    // Disables automatic session tracking
    ),
)
self.analytics = Analytics(configuration: config)
```

The corresponding Objective-C snippet is shown below:

```objectivec
RSSConfigurationBuilder *builder = [[RSSConfigurationBuilder alloc] initWithWriteKey:writeKey dataPlaneUrl:dataPlaneUrl];

RSSSessionConfigurationBuilder *sessionBuilder = [RSSSessionConfigurationBuilder new];
[sessionBuilder setAutomaticSessionTracking:NO];
[builder setSessionConfiguration: [sessionBuilder build]];

self.analytics = [[RSSAnalytics alloc] initWithConfiguration:[builder build]];
```
{{% /tab %}}
{{< /tabs >}}

### Supported APIs

RudderStack provides the following APIs for manual session tracking:

| API | Description |
| :----| :-----|
| `sessionStart` | Used to start a new manual session. It takes `sessionId` as an optional parameter. If you do not provide any `sessionId`, then the  current timestamp is used as the `sessionId` instead. |
| `endSession` | Must be called to end a session manually as there is no concept of automatic session end due to timeout. |

### Persistence scope

The persistence scope of manual session tracking depends on the status of [automatic session tracking](#automatic-session-tracking):

- If automatic session tracking is **enabled** and you call the `startSession`API, then RudderStack **disables** automatic session tracking. Once you restart the app, the SDK resumes automatic session tracking **if** it is still enabled.
- If automatic session tracking is **enabled**, calling the `endSession` API causes the active session to end. The automatic session tracking resumes once the app is relaunched, provided automatic session tracking is still enabled.
- If automatic session tracking is **disabled** and you call the `startSession`() API, the manual session is active until you end it by calling the `endSession` API.

### Sample snippets

{{< tabs tabTotal="2" >}}
{{% tab tabName="Android (Kotlin)" %}}
```kotlin
// Starts a new manual session and automatically assigns a session ID.
rudderClient.startSession()

// Passes a custom session ID while creating a new session.
rudderClient.startSession(sessionId)

// Ends the user session and clears the session ID.
rudderClient.endSession()
```

The corresponding Java snippet is shown below:

```java
// Starts a new manual session and automatically assigns a session ID.
rudderClient.startSession();

// Passes a custom session ID while creating a new session.
rudderClient.startSession(sessionId);

// Ends the user session and clears the session ID.
rudderClient.endSession();
```

{{% /tab %}}
{{% tab tabName="iOS (Swift)" %}}
```swift
// Starts a new manual session and automatically assigns a session ID.
analytics.startSession()

// Passes a custom session ID while creating a new session.
analytics.startSession(sessionId)

// Ends the user session and clears the session ID.
analytics.endSession()
```

The corresponding Objective-C snippet is shown below:

```objectivec
// Starts a new manual session and automatically assigns a session ID.
[analytics startSession];

// Passes a custom session ID while creating a new session.
[analytics startSession:sessionId];

// Ends the user session and clears the session ID.
[analytics endSession];
```
{{% /tab %}}
{{< /tabs >}}

## Background events and session lifetime

From Android (Kotlin) SDK **1.7.0** and iOS (Swift) SDK **1.3.0**, background events no longer extend the session lifetime by default. If your use case requires background events to extend session lifetime — for example, personalized push notification flows — set `updateSessionOnBackgroundEvents` to `true` in `SessionConfiguration`.

{{< tabs tabTotal="2" >}}
{{% tab tabName="Android (Kotlin)" %}}
```kotlin
// Default — background events do not extend session lifetime
val sessionConfiguration = SessionConfiguration(
    sessionTimeoutInMillis = 300_000L
)

// Opt in — background events extend the session lifetime
val sessionConfiguration = SessionConfiguration(
    sessionTimeoutInMillis = 300_000L,
    updateSessionOnBackgroundEvents = true
)
```

The corresponding Java snippet is shown below:

```java
// Default — background events do not extend session lifetime
SessionConfiguration sessionConfiguration = new SessionConfigurationBuilder()
    .setSessionTimeoutInMillis(300000L)
    .build();

// Opt in — background events extend the session lifetime
SessionConfiguration sessionConfiguration = new SessionConfigurationBuilder()
    .setSessionTimeoutInMillis(300000L)
    .setUpdateSessionOnBackgroundEvents(true)
    .build();
```
{{% /tab %}}
{{% tab tabName="iOS (Swift)" %}}
```swift
// Default — background events do not extend session lifetime
let sessionConfiguration = SessionConfiguration(
    sessionTimeoutInMillis: 300_000
)

// Opt in — background events extend the session lifetime
let sessionConfiguration = SessionConfiguration(
    sessionTimeoutInMillis: 300_000,
    updateSessionOnBackgroundEvents: true
)
```

The corresponding Objective-C snippet is shown below:

```objectivec
// Default — background events do not extend session lifetime
RSSSessionConfiguration *config = [[[RSSSessionConfigurationBuilder alloc] init] build];

// Opt in — background events extend the session lifetime
RSSSessionConfiguration *config = [[[[RSSSessionConfigurationBuilder alloc] init]
    setUpdateSessionOnBackgroundEvents:YES]
    build];
```
{{% /tab %}}
{{< /tabs >}}

## Get the session ID

You can use the `sessionId` API to retrieve the current session ID for the manual or automatic session, as shown:

{{< tabs tabTotal="2" >}}
{{% tab tabName="Android (Kotlin)" %}}
```kotlin
val sessionId = analytics.sessionId
```

The corresponding Java snippet is shown below:

```java
Long sessionId = analytics.getSessionId();
```
{{% /tab %}}
{{% tab tabName="iOS (Swift)" %}}
```swift
var sessionId = analytics.sessionId
```

The corresponding Objective-C snippet is shown below:

```objectivec
NSNumber *sessionId = analytics.sessionId;
```
{{% /tab %}}
{{< /tabs >}}

## Effect of `reset` API on session tracking

Calling the [`reset`]({{< ref "sources/event-streams/sdks/mobile-sdk-apis/reset.md" >}}) API causes the session to refresh irrespective of whether it is automatic or manual — this means RudderStack restarts the session and generates a new session ID.

Note that:

- The [`identify`]({{< ref "sources/event-streams/sdks/mobile-sdk-apis/identify.md" >}}) API calls `reset` internally when a previously identified user's `userId` changes, for example, `User A` > `User B`. In this case, the session is refreshed along with all the other user data.
- Calling `identify` on an anonymous user (no previous `userId`) does not trigger a reset — the existing session continues uninterrupted.

See the [`reset` API documentation]({{< ref "sources/event-streams/sdks/mobile-sdk-apis/reset.md#implicit-reset-via-identify" >}}) for more information on the implicit reset behavior and how to selectively preserve specific data during a user switch.

<br />
