Menu
Grafana Cloud

Session tracking

Note

Session tracking requires Faro Web SDK version 1.3.6 or greater. In order to visualize your data in the Grafana Cloud Frontend Observability plugin, you must instrument your frontend application with at least v1.3.6.

The session tracking instrumentation reports the change of the session meta as an event. This is useful for RUM because you can track when a new session starts.

Using the session tracking instrumentation, you can correlate errors, logs, and events that occurred for a particular user during a single session using the application.

In order for the session tracking instrumentation to work correctly, the session meta should not be removed.

What is a session?

A session is defined as the time that a user spends in a Frontend App from start to finish or timeout. Sessions are either created or resumed when a user visits and uses the app.

An individual session ends after a maximum lifetime of 4 hours or after an inactivity timeout of 15 minutes. When the user returns after the timeout period elapses, the SDK automatically creates a new user session.

How session tracking works

Faro automatically creates a new session if a user visits a page, or depending on the chosen mode, picks the last session of a recurring user.

A Faro session has a max. lifetime of 4 hours and a max. inactivity time of 15 minutes.
The maximum time Faro keeps a tracked session (see below) is 45 minutes by default but can be configured.

If either of the session timeouts is reached, Faro creates a new session and updates the session meta object with the new session id as well as the previous session id. The latter gets added via the previousSession attribute.
Every time a new session is created Faro calls the optional onSessionChange callback and provides the oldSession and newSession meta as parameters. The oldSession meta is null when the initial session is created.

The Faro receiver also checks the related session of every beacon sent by Faro for its validity, that is the validity of the max. lifetime and activity-time.
If a beacons session is invalid it drops it.
The web-sdk takes care of creating new sessions if either of the aforementioned time ranges is reached, so there should never be a need for the receiver to drop beacons.

Faro attaches the x-faro-session-id custom header, with the value set to the current session-id, to each HTTP request sent to the collector URL, so that the backend can keep track of user-sessions and enforce constraints.

To help users identify lifecycle events, Faro sends different lifecycle events throughout the life of a session.

The lifecycle events are:

  • session_start: if no session is found in web-storage during the initialization phase
  • session_resume: if a valid session is found in web-storage during the initialization phase
  • session_extend: if Faro auto-creates a new session because one of the session timeouts is reached or if setSession(...) is called manually

Faro provides two modes for session tracking, which are described in the next two sections.

Tracked sessions mode

If the tracked sessions mode is enabled, Faro persists session information in the browsers Local Storage. This enables session information to outlive page reloads as well as to sync sessions between the different browsing contexts like tabs or new windows from within the same browser.

Faro also keeps the session for a configurable amount of time so it can pick up the session in case a site visitor closes the browser and returns after some time.

Note:

Faro can not differentiate session between users. So if different users use the same browser, Faro picks up the last persisted valid session. This can lead to a situation where different users share the same session Id. Faro provides multiple ways to deal with the situation, depending on your needs. See the examples at the end of the page.

Volatile sessions mode

If the volatile sessions mode is enabled, Faro stores session information in the browsers Session Storage. This means session information can outlive page reloads within the same site but it doesn’t persist the session between browsing context like other tabs or windows. Opening a new tab or window with the same site creates a new session.

After closing a tab the session is gone, which means it is not possible to have a recurring visitor to pick up on the last session.

Sampling

Faro facilitates sampling by making sampling decisions on a per-session basis. Within a sampled session, every signal is transmitted, while signals from un-sampled sessions are discarded.

Sampling decisions in Faro are determined by the configured sampling rate or a custom sampler function. The sampling rate can be set between 0 and 1, where the sampling function must produce a value within this range. A value of 0 (0%) implies that no signals are sent, while a value of 1 (100%) ensures that all signals are transmitted. By default, the sampling rate is set to 1 (100%).

The sampler function computes a sampling decision based on other properties for tailored sampling decisions. It gets contextual information injected, which currently contains multiple Faro Metadata objects.

A sampling decision is calculated at the following points in time:

  • On page load, when Faro is initialized and an invalid session is found in web-storage.
  • On session extend, this is when Faro auto-creates a new session because one of the session timeouts is reached or if setSession(...) is called manually.

Configuration options

The session manager can be configured with the sessionTracking object via the Faro setup function.

It provides the following options:

OptionsDescriptionDefault value
enabledEnable or disable session managementfalse
persistentWether to use tracked or volatile sessionsfalse
sessionInitial session object, only for very special demandsundefined
maxSessionPersistenceTimeHow long to keep a session to identify a recurring visitor (tracked sessions only)15 minutes + 1 minute buffer
onSessionChangeCalled each time a new session is createdundefined
samplingRateNumber between 0 (0% of signals sent) and 1 (100% of signals sent).1
samplerCalculate a sampling decision based on other properties. Should return number between 0 and 1.undefined
generateSessionIdIf present, Faro calls this function each time it needs to create a new session id.undefined
ts
sessionTracking?: {
  enabled?: boolean;
  persistent?: boolean;
  session?: MetaSession;
  maxSessionPersistenceTime?: number;
  onSessionChange?: (oldSession: MetaSession | null, newSession: MetaSession) => void;
  samplingRate?: number;
  sampler?: (context: SamplingContext) => number;
  generateSessionId?: () => string;
};

Add the session tracking instrumentation

The following session tracking instrumentation is enabled by default. No additional configuration is required.

ts
initializeFaro({
  url: 'https://my-domain.my-tld/collect/{app-key}',
  app: {
    name: 'my-app',
  },
});

Note

If you overwrite the instrumentations array when you initialize the Grafana Faro Web SDK, you must manually include the Session tracking instrumentation.

To manually include the session instrumentation, use the following getWebInstrumentations helper function.

ts
initializeFaro({
  url: 'https://my-domain.my-tld/collect/{app-key}',
  app: {
    name: 'my-app',
  },
  instrumentations: [...getWebInstrumentations()],
});

Alternatively, if you want to fine-tune which instruments are enabled, you can use the following SessionInstrumentation class.

ts
initializeFaro({
  url: 'https://my-domain.my-tld/collect/{app-key}',
  app: {
    name: 'my-app',
  },
  instrumentations: [new SessionInstrumentation()],
});

Configure the session tracking instrumentation

ts
initializeFaro({
  ...
  sessionTracking?: {
    enabled: true;
    persistent: true;
    onSessionChange: (oldSession: MetaSession | null, newSession: MetaSession) => {
      console.log(`Session ${oldSession == null ? 'created' : 'changed'}`, {oldSession, newSession})
    } ;
  };
});
If multiple users share the same browser

If persistent sessions are activated, Faro persists the users session in the browser Local Storage. If a user opens the site, Faro selects the session from storage if it’s valid or creates a new one if not.

But if multiple users share the same browser, this may lead to a situation where user A leaves the site, then a bit later user B navigates to that site. So Faro selects the valid persisted session. This causes the user B having the same session id as user A.

Since Faro can not derive if a visitor is the same person or a new one, you need to take care of this. Faro provides some options to mitigate the issue, which are the following:

First possibility is to define a shorter maxSessionPersistenceTime (default 15 minutes + 1 minute buffer).

ts
initializeFaro({
  ...
  sessionTracking?: {
    enabled: true;
    persistent: true;
    maxSessionPersistenceTime: 1 * 60 * 1000 // 1 minute
    onSessionChange: (oldSession: MetaSession | null, newSession: MetaSession) => {
      console.log(`Session ${oldSession == null ? 'created' : 'changed'}`, {oldSession, newSession})
    } ;
  };
});

Second possibility is to delete the Session manually when you consider a session as finished.
The easiest way is to use the static method removeUserSession() on PersistentSessionsManager.
This removes the session from Local Storage and Faro creates a new one on the next page load.

ts
import { PersistentSessionsManager } from '@grafana/faro-web-sdk';

function handleSessionClose() {
  PersistentSessionsManager.removeUserSession();
}

Use the sampler function to calculate tailored sampling decisions

Use a custom sampler function to calculate a tailored sampling decision.

ts
initializeFaro({
  ...
  user: {
    attributes: {
      planet: 'mars',
    },
  },
  ...
  sessionTracking?: {
    enabled: true;
    onSessionChange: (oldSession: MetaSession | null, newSession: MetaSession) => {
      console.log(`Session ${oldSession == null ? 'created' : 'changed'}`, {oldSession, newSession})
    };
    sampler(context) {
      const planet = context.metas.user?.attributes?.['planet'];

      if (!planet) {
         return 0; // 0%
      }

      if (planet === 'mars') {
         return 0.8; // 80%
      }

      if (planet === 'moon') {
         return 0.3; // 30%
      }

      if (planet === 'earth') {
         return 0.1; // 10%
      }

      return 1;
    },
  };
});

Create custom session ids

In case a custom id scheme is needed, Faro provides the generateSessionId() function. If this function is present in the configuration object, Faro always calls this function instead of its internal sessionId generator.

ts
initializeFaro({
  ...
  sessionTracking?: {
    generateSessionId() {
      // generate and return custom sessionId here.
    }
  };
});