npm package: @perceptinsight/percept-react-native
Description: Official Percept React Native SDK
Author: Percept
Latest version: 3.0.1

# percept-react-native

Official Percept React Native SDK

## Quick Start Guide

### 1. Install

```sh
npm install @perceptinsight/percept-react-native
or
yarn add @perceptinsight/percept-react-native
```

This package has dependency on [@react-native-async-storage/async-storage](https://www.npmjs.com/package/@react-native-async-storage/async-storage) and [react-native-device-info](https://www.npmjs.com/package/react-native-device-info). To install, run the following commands:

```sh
npm install @react-native-async-storage/async-storage react-native-device-info
or
yarn add @react-native-async-storage/async-storage react-native-device-info

npx pod-install
```

### 2. Initialize Percept SDK

```js
import Percept from '@perceptinsight/percept-react-native';

await Percept.init('Your Project Token');
```

`init` method takes an optional `initOptions` param as second argument which can be used to configure auto tracked events.
`initOptions` properties:

| property                         | required | type                   | default value |
| -------------------------------- | -------- | ---------------------- | ------------- |
| `autoCaptureAppLifecycleEvents`  | `false`  | `boolean`              | `true`        |
| `autoCaptureUnhandledExceptions` | `false`  | `boolean`              | `true`        |
| `eventsFlushThresholdInSeconds`  | `false`  | `number`               | 10            |
| `autoTrackApiCalls`              | `false`  | `boolean`              | `false`       |
| `apiTrackingBlocklist`           | `false`  | `string` \| `string[]` | `[]`          |
| `autoFlushBatchSize`             | `false`  | `number`               | 30            |
| `enableLogs`                     | `false`  | `boolean`              | false         |
| `enableExperiment`               | `false`  | `boolean`              | `false`       |
| `experimentFetchedCb`            | `false`  | `function`             | `undefined`   |
| `experimentRefetchIntervalMin`   | `false`  | `number`               | `undefined`   |

[See what events are tracked by these](#events-auto-tracked-by-sdk)

> NOTE: This is an asynchronous call

### 3. Set user id

After successfully initializing the SDK, On login set User id using the following function.

```JS
await Percept.setUserId('U1');
```

You can also pass user properties as part of this call as second parameter.

```JS
import Percept, {PerceptUserPropertyKeys} from '@perceptinsight/percept-react-native'

await Percept.setUserId('U1', {[PerceptUserPropertyKeys.NAME]: 'Test User'});
```

> NOTE: This is an asynchronous call

### 4. Set user properties

use `setUserProperties` method to set properties on the user profile created by `setUserId`

```JS
// first call this method
await Percept.setUserId('U1');

// sets user `isVerifiedAccount` property to true
Percept.setUserProperties({isVerifiedAccount: true})
```

We expose some default user property keys in `PerceptUserPropertyKeys`. Please use them as this helps in standarization and usage in the Engage feature provided by Percept.

```JS
import Percept, {PerceptUserPropertyKeys} from '@perceptinsight/percept-react-native'

// first call this method
await Percept.setUserId('U1');

// sets user `phone` property to '123456789' and `isVerifiedAccount` property to true
Percept.setUserProperties({[PerceptUserPropertyKeys.PHONE]: 123456789, isVerifiedAccount: true})
```

### 5. Send Event

Let's get started by sending event data. You can send an event from anywhere in your application. After initializing the library, Percept will automatically [track some properties by default](https://github.com/udaan-com/percept-react-native/blob/6968994a84075ae764f29e2df06d37df7f95f2bb/src/types.ts#L1).

```JS
// Track only event-name
Percept.capture('Referral Banner Click');
// Track event-name with property
Percept.capture('Screen View', {'screenName': 'Homepage'});
```

### 6. Timing Events

You can track the time it took any action to complete using `timeEvent` method. Calling this method will mark the start of the action and subsequent call to capture method will mark the end. The time duration is recorded in `pi_timed_event_duration` property.

```JS
// Start the time for the event 'Image Upload'
Percept.timeEvent('Image Upload');
// ... some time later. This call capture the 'Image Upload' event with 'pi_timed_event_duration' property
Percept.capture('Image Upload');
```

### 7. Set Global Property

Set global property which will be passed with all subsequent events

```JS
await Percept.setGlobalProperty('global-property-key', 'value');
```

### 8. Set Multiple Global Property

Call this method to bulk set multiple global properties

```JS
await Percept.setMultipleGlobalProperty([{key: 'global-prop-key-1', value: 'value 1'}, {key: 'global-prop-key-2', value: 'value 2'}, {key: 'global-prop-key-3', value: 'value 3'}]);
```

### 9. Remove Global Property

Remove any previously set global property

```JS
await Percept.removeGlobalProperty('global-property-key');
```

### 10. Get all global properties

Get all global properties

```JS
await Percept.getAllGlobalProperties();
```

### 11. Clear

Call clear function on logout to delete all user related information

```JS
await Percept.clear()
```

## Integrating Engage module

#### Firebase messaging module is prereuisite for this. Kidnly follow the steps mentioned [here](https://rnfirebase.io/messaging/usage)

Once you are done with FCM integration, follow the following steps to streamline push notification functionality and monitor their impact and attribution

#### 1. Pass the fcm token received from Firebase to Percept

```JS
  import messaging from '@react-native-firebase/messaging';

  // get token from firebase messaging
  const fcmToken = await messaging().getToken();
  // set percept fcm token
  if (fcmToken && fcmToken.length > 0) {
    Percept.setUserProperties({
      [PerceptUserPropertyKeys.DEVICE_TOKEN]: fcmToken,
    });
  }

  // update token passed to percept on token refresh
  messaging().onTokenRefresh(token => {
    Percept.setUserProperties({
      [PerceptUserPropertyKeys.DEVICE_TOKEN]: token,
    });
  });
```

> NOTE: Do not pass fcm token to Percept SDK before calling Percept.setUserId

#### 2. Notify Percept sdk when app is in foreground when notification is received

```JS
    import messaging from '@react-native-firebase/messaging';
    import Percept from '@perceptinsight/percept-react-native';

    // app was in quit state when notification arrived and click on notification opened the app
    messaging()
      .getInitialNotification()
      .then(async remoteMessage => {
        if(remoteMessage) {
          Percept.pnViewedHandler(remoteMessage as any, YOUR_PERCEPT_KEY, PerceptPNAttributionState.TERMINATED);
        }
      });

    // app was in background when notification arrived and click on notification opened the app
    messaging().onNotificationOpenedApp(async remoteMessage => {
      Percept.pnViewedHandler(remoteMessage as any, YOUR_PERCEPT_KEY, PerceptPNAttributionState.BACKGROUND);
    });

    // message listener foreground. app was in foreground when notification arrived
    messaging().onMessage(async remoteMessage => {
      Percept.pnViewedHandler(remoteMessage as any, YOUR_PERCEPT_KEY, PerceptPNAttributionState.FOREGROUND);
    });
```

#### 3. Notifying SDK when notification received in terminated/background state for better attribution

```JS
  import messaging from '@react-native-firebase/messaging';
  import Percept from '@perceptinsight/percept-react-native';

  // Register background handler. Read more here-> https://rnfirebase.io/messaging/usage#background--quit-state-messages
  // Important information on iOS handling -> https://rnfirebase.io/messaging/usage#background-application-state
  messaging().setBackgroundMessageHandler(async remoteMessage => {
   Percept.pnReceivedHandler(remoteMessage as any,YOUR_PERCEPT_KEY);
});


```

NOTE: Since the Push Notification events can be triggered before Percept initialisation, we recommend sending Percept Api token as part of the api call

## Events auto tracked by sdk

| event name            | `initOption` key to control      | description                                                          |
| --------------------- | -------------------------------- | -------------------------------------------------------------------- |
| App Opened            | `autoCaptureAppLifecycleEvents`  | Triggered when percept sdk is initialized                            |
| App Active            | `autoCaptureAppLifecycleEvents`  | Triggered when app comes to foreground                               |
| App Backgrounded      | `autoCaptureAppLifecycleEvents`  | Triggered when app goes to background                                |
| Application Installed | `autoCaptureAppLifecycleEvents`  | Triggered when app is installed for the first time                   |
| Application Updated   | `autoCaptureAppLifecycleEvents`  | Triggered when app is updated                                        |
| Unhandled JS Error    | `autoCaptureUnhandledExceptions` | Triggered when some unhandled runtime error takes place in JS thread |
| $Fetch                | `autoTrackApiCalls`              | Triggered when any api call is made                                  |

## Custom app and device properties attached by SDK

These properties are available in all events

| property               | description                                                                                                                                                                                                                                      |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| pi_app_build           | Build number like "2.3.7" or "237"                                                                                                                                                                                                               |
| pi_app_name            | Application name                                                                                                                                                                                                                                 |
| pi_app_version         | Human friendly app version like "2.3.7"                                                                                                                                                                                                          |
| pi_carrier             | Network operator name                                                                                                                                                                                                                            |
| pi_device_manufacturer | Device manufacturer. Ex. 'Google', 'Apple'                                                                                                                                                                                                       |
| pi_device_name         | Device model name                                                                                                                                                                                                                                |
| pi_first_install_time  | The time at which the app was first installed, in milliseconds                                                                                                                                                                                   |
| pi_install_referrer    | Only available on android. Gets the referrer string upon application installation. If the app was installed from `https://play.google.com/store/apps/details?id=com.myapp&referrer=my_install_referrer` the result will be "my_install_referrer" |
| pi_is_location_enabled | Boolean to know whether location is enabled on device or not                                                                                                                                                                                     |
| pi_os_name             | Operating system name like iOS or Android                                                                                                                                                                                                        |
| pi_os_version          | Operating system version "7.1.3"                                                                                                                                                                                                                 |
|                        |                                                                                                                                                                                                                                                  |

### Folowing properties are part of `Unhandled JS Error` event:

| property                   | description                       |
| -------------------------- | --------------------------------- |
| pi_is_fatal                | Fatal error boolean               |
| pi_unhandled_error_event   | Stringified captured error object |
| pi_unhandled_error_name    | Error name                        |
| pi_unhandled_error_stack   | Stringified error stack           |
| pi_unhandled_error_message | Error message                     |

### Engage related properties

| Property_name        | Description                                     |
| -------------------- | ----------------------------------------------- |
| pi_pn_isPNAttributed | Is the current session PN triggered             |
| pi_pn_campaignId     | CampaignId associated with the notificaiton     |
| pi_pn_campaignName   | CampaignName associated with the notificaiton   |
| pi_pn_campaignSource | CampaignSource associated with the notificaiton |

### Network calls tracking

Network calls are tracked as `$Fetch` event. It is disabled by default and can be enabled by setting `autoTrackApiCalls` to true in init options. Percept Insight only tracks fetch/xhr calls and static resource calls are not tracked.\
You can ask Percept Insight to not track certain api calls by passing the relevant url string/regex or string array in `apiTrackingBlocklist` parameter in init options.

Following properties are available as part of this event:
| property |
| -------------------------- |
| pi_fetch_url |
| pi_fetch_status_code |
| pi_fetch_request_type |
| pi_fetch_successful |
| pi_fetch_time_taken |

## Handling Experiments

### 1. Enabling Experiments

To enable experiment tracking, set the `enableExperiment` option to `true` in the `initOptions`. You can also specify a callback function to handle the experiment data when it is fetched.

```JS
const initOptions = {
  enableExperiment: true,
  experimentFetchedCb: (data) => {
    const { experimentData, experimentUserType, isExperimentDataResolved } = data;
    if (isExperimentDataResolved) {
      console.log('Experiment data fetched:', experimentData);
    } else {
      console.log('Experiment data could not be resolved.');
    }
  },
  experimentRefetchIntervalMin: 10, // Refetch experiment data every 10 minutes
};

Percept.init('Your Project Token', initOptions);
```

Note: The `experimentRefetchIntervalMin` option sets the interval in minutes for automatically refetching experiment data. The interval must be at least 5 minutes. If a value less than 5 is provided, it will be automatically set to 5 minutes and a warning will be logged.

### 2. Fetching Experiment Data

You can fetch experiment data at any time using the `getExperiment` method. This method returns a promise that resolves to the variant data for the specified experiment.

```JS
const experimentName = 'example-experiment';
const variant = await Percept.getExperiment(experimentName);

if (variant) {
  console.log(`User is in variant: ${variant}`);
} else {
  console.log('No variant data available');
}
```

### 3. Refetching Experiment Data

If you have set the `experimentRefetchIntervalMs` option, the SDK will automatically refetch the experiment data at the specified interval. You can also manually refetch the experiment data using the `refetchExperiment` method.

```JS
await Percept.refetchExperiment();
```

### 4. Getting All Active Experiments

You can get all active experiments and their variants using the `getAllActiveExperiments` method.

```JS
const activeExperiments = await Percept.getAllActiveExperiments();
console.log('Active experiments:', activeExperiments);
```

### 5. Getting Experiment User Type

You can get the user type for experiments using the `getExperimentUserType` method.

```JS
const userType = await Percept.getExperimentUserType();
console.log('Experiment user type:', userType);
```