# Conviva React Native App Analytics - Developer Integration Guide

Use the Conviva React Native App Analytics SDK to auto-collect events and track application-specific events and state changes. The React Native bridges are internally built on top of the [Android](https://github.com/Conviva/conviva-android-appanalytics) and [iOS](https://github.com/Conviva/conviva-ios-appanalytics) native sensors.

**Table of Contents**
- [Quick Start](#quick-start)
- [More Features](#more-features)
- [Error Tracking](#error-tracking)
- [Auto-collected Events](#auto-collected-events)
- [FAQ](#faq)

---

## Quick Start

### Supported Platforms

| Platform | Minimum Version |
|---|---|
| Android | Android 5.0 (API level 21) |
| iOS / tvOS | iOS 9.0 / tvOS 9.0 |
| React Native | 0.60+ (auto-linking supported) |
| Expo bare workflow | Supported (requires native setup below) |
| Expo managed workflow | Run `npx expo prebuild` first to generate native folders |

### Expo Projects

**Bare workflow** (created with `expo init --template bare-minimum` or ejected): The `android/` and `ios/` folders exist. Follow all steps below as for standard React Native.

**Managed workflow** (created with `npx create-expo-app` without ejecting, no `android/` or `ios/` folders): Native folders must be generated before native setup is possible.

```bash
npx expo prebuild
```

After prebuild, the project behaves as Expo bare workflow. Complete all steps below.

Steps 1 (add to `package.json`), 5 (Babel plugin), and 6 (React Navigation setup) apply to both managed and bare Expo workflows regardless of prebuild status.

### 1. Add the npm Package to `package.json`

> **Do not run `npm install` / `yarn add` for this package in isolation.** Instead, add the entries to `package.json` manually and run the install command once after all edits are complete.

Add to `dependencies` in `package.json`:
```json
"@convivainc/conviva-react-native-appanalytics": "<version>"
```

Then run the install command from the project root (use whichever matches your project):
```bash
npm install
```
```bash
yarn
```

After installing, run pod install for iOS:
```bash
npx pod-install
```

### 2. Android Native Setup

#### 2a. Determine Your App Type

Before adding the tracker dependency, identify whether your Android app is **standard React Native** or **hybrid**:

| App Type | Description |
|---|---|
| **Standard React Native** | All screens are React Native. The only Activity is `MainActivity` extending `ReactActivity`. No native Android Activities outside the RN bridge. |
| **Hybrid** | Contains native Android Activities (Java/Kotlin) that run outside the React Native bridge -- for example, a native splash screen, login screen, or settings activity. |

**Standard React Native apps:** The React Native bridge initializes the tracker automatically when you call `createTracker(...)` in JavaScript (Step 4). You do not need to add the tracker dependency or call `createTracker` natively. Skip ahead to [Step 2b](#2b-add-the-gradle-plugin-for-button-click-and-network-request-auto-collection).

**Hybrid apps with multiple Activities:** The tracker must also be initialized natively so that native Activities are tracked from app start, before the React Native bridge loads. Continue with the steps below.

#### Add the Tracker Dependency (Hybrid Apps only)

In `android/app/build.gradle`, add to `dependencies {}`:

```groovy
dependencies {
    // ...
    implementation 'com.conviva.sdk:conviva-android-tracker:<ANDROID_TRACKER_VERSION>'
}
```

> **Important:** `<ANDROID_TRACKER_VERSION>` is the version of the Android native tracker artifact -- it is **independent of the npm package version** (`CONVIVA_RN_VERSION`). Find the correct version at [GitHub Releases](https://github.com/Conviva/conviva-android-appanalytics/releases). Do not use the npm version number here.

#### Initialize the Native Tracker (Hybrid Apps only)

After adding the dependency, initialize the tracker in your Android `Application` class's `onCreate()`. This ensures all native Activities are covered from app start.

**Find your Application class:** Check the `android:name` attribute on the `<application>` tag in `android/app/src/main/AndroidManifest.xml`. If no custom Application class exists, use the MAIN/LAUNCHER Activity.

**Java:**
```java
// Exception is java.lang.Exception — auto-imported in every Java file, no import statement needed
import com.conviva.apptracker.ConvivaAppAnalytics;
import com.conviva.apptracker.controller.TrackerController;

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        try {
            TrackerController tracker = ConvivaAppAnalytics.createTracker(this, "YOUR_CUSTOMER_KEY", "YOUR_APP_NAME");
            if (tracker == null) {
                // handle initialization failure
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

**Kotlin:**
```kotlin
// Exception is kotlin.Exception — auto-imported in every Kotlin file, no import statement needed
import com.conviva.apptracker.ConvivaAppAnalytics

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        try {
            val tracker = ConvivaAppAnalytics.createTracker(this, "YOUR_CUSTOMER_KEY", "YOUR_APP_NAME")
            if (tracker == null) {
                // handle initialization failure
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}
```

> Use the same `YOUR_CUSTOMER_KEY` and `YOUR_APP_NAME` values as in your JavaScript `createTracker(...)` call (Step 4). Do not hardcode these -- they must match exactly.
>
> Do not create a new `Application` class if one does not exist -- ask your developer to create one, or use the MAIN/LAUNCHER Activity.

#### 2b. Add the Gradle Plugin (for button click and network request auto-collection)

**For Android Gradle Plugin (AGP) >= 8.0 - use plugin version 0.3.x:**

In the **root** `android/build.gradle`:
```groovy
buildscript {
    dependencies {
        // ...
        classpath 'com.conviva.sdk:android-plugin:0.3.x'
    }
}
```

**For AGP below 8.0 - use plugin version 0.2.x:**

In the **root** `android/build.gradle`:
```groovy
buildscript {
    dependencies {
        // ...
        classpath 'com.conviva.sdk:android-plugin:0.2.x'
    }
}
```

In `android/app/build.gradle`, apply the plugin at the end of the plugins section:
```groovy
apply plugin: 'com.conviva.sdk.android-plugin'
```

Or in Kotlin DSL (`android/app/build.gradle.kts`):
```kotlin
plugins {
    // ...
    id("com.conviva.sdk.android-plugin")
}
```

#### 2c. ProGuard / R8 Rules

Append to `android/app/proguard-rules.pro`:
```proguard
-keepnames class * extends android.view.View
-keep,allowshrinking class com.conviva.** { *; }
```

### 3. iOS Native Setup

The `ConvivaAppAnalytics` pod is automatically resolved via `RNConvivaAppAnalytics.podspec` when `npx pod-install` runs. No manual Podfile changes are needed.

Verify that `ios/Podfile` has `platform :ios, '9.0'` or higher.

#### Multi-SDK Runtime Stability (Info.plist)

If your app integrates multiple SDKs that use ISA-swizzling (e.g., analytics, crash reporting, or A/B testing SDKs), add the following key to `ios/<YourAppName>/Info.plist` to prevent runtime crashes:

```xml
<key>CATGeneratedClassDisposeDisabled</key>
<true/>
```

This setting causes the SDK to retain a small, predictable amount of class metadata in memory, which improves runtime stability when multiple swizzling SDKs are present.

### 4. Initialize the Tracker

Call `createTracker` once, at app startup, before any screen rendering. Place it at the top of your root component file (`App.js`, `App.tsx`, or `index.js`).

**JavaScript:**
```js
import { createTracker } from '@convivainc/conviva-react-native-appanalytics';

let tracker;
try {
  tracker = createTracker('YOUR_CUSTOMER_KEY', 'YOUR_APP_NAME');
  if (!tracker) {
    console.error('Tracker initialization returned null');
  }
} catch (error) {
  console.error(error);
}
```

**TypeScript:**
```ts
import { createTracker, ReactNativeTracker } from '@convivainc/conviva-react-native-appanalytics';

let tracker: ReactNativeTracker | undefined;
try {
  tracker = createTracker('YOUR_CUSTOMER_KEY', 'YOUR_APP_NAME');
  if (!tracker) {
    console.error('Tracker initialization returned null');
  }
} catch (error) {
  console.error(error);
}
```

> **YOUR_CUSTOMER_KEY** - A string to identify your Conviva account. Use separate keys for debug and production. Find your keys on the Pulse account info page.
> **YOUR_APP_NAME** - A string value that uniquely identifies your app across platforms.

### 5. Babel Plugin Setup (Button Clicks and `displayName` Auto-detection)

The required Babel configuration depends on your installed version of `@convivainc/conviva-react-native-appanalytics`. Check the version in your `package.json`.

#### For version <= 0.2.8

Add two separate plugins to your `babel.config.js` -- one for button click auto-detection and one for `displayName` injection:

**`babel.config.js`:**
```js
module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: [
    './node_modules/@convivainc/conviva-react-native-appanalytics/instrumentation/index.js',
    'add-react-displayname',
  ],
};
```

Add the following to `devDependencies` in `package.json`:
```json
"babel-plugin-add-react-displayname": "0.0.5",
"babel-types": "^6.26.0",
"babel-template": "^6.26.0"
```

- `babel-plugin-add-react-displayname` `0.0.5` is the final published version of the package.
- `babel-types` and `babel-template` at `^6.26.0` are required by `instrumentation/index.js`; they are legacy Babel 6 packages not installed automatically in Babel 7 projects.

Then run `npm install` (or `yarn`) from the project root.

#### For version >= 0.3.0

A single unified Conviva plugin handles both button click auto-detection and `displayName` injection. **No extra dependencies are needed in the app.**

**`babel.config.js`:**
```js
module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: [
    '@convivainc/conviva-react-native-appanalytics/plugin',
  ],
};
```

`displayName` auto-detection is absorbed internally by the Conviva plugin. Do **not** add `add-react-displayname`, `babel-plugin-add-react-displayname`, or `@babel/plugin-transform-react-display-name` to `plugins` or `devDependencies`.

---

After updating `babel.config.js`, restart Metro with `--reset-cache` (applies to both versions):
```bash
npx react-native start --reset-cache
```

The Conviva instrumentation plugin enables auto-detection of button clicks for: `Button`, `TouchableHighlight`, `TouchableOpacity`, `TouchableWithoutFeedback`, and `TouchableNativeFeedback` components.

### 6. React Navigation Setup (Screen View Auto-detection)

#### React Navigation >= 5

Wrap your `NavigationContainer` with `withReactNavigationAutotrack`. The original `NavigationContainer` import must remain -- it is passed to the HOC and used internally.

**JavaScript:**
```js
import { NavigationContainer } from '@react-navigation/native';
import {
  withReactNavigationAutotrack,
  autocaptureNavigationTrack,
} from '@convivainc/conviva-react-native-appanalytics';

let ConvivaNavigationContainer;
try {
  ConvivaNavigationContainer =
    withReactNavigationAutotrack(autocaptureNavigationTrack)(NavigationContainer);
  if (!ConvivaNavigationContainer) {
    console.error('Navigation container setup returned null');
  }
} catch (error) {
  console.error(error);
}
```

**TypeScript** -- add `as typeof NavigationContainer` to preserve prop types for JSX type-checking:
```ts
import { NavigationContainer } from '@react-navigation/native';
import {
  withReactNavigationAutotrack,
  autocaptureNavigationTrack,
} from '@convivainc/conviva-react-native-appanalytics';

let ConvivaNavigationContainer: typeof NavigationContainer | undefined;
try {
  ConvivaNavigationContainer =
    withReactNavigationAutotrack(autocaptureNavigationTrack)(NavigationContainer) as typeof NavigationContainer;
  if (!ConvivaNavigationContainer) {
    console.error('Navigation container setup returned null');
  }
} catch (error) {
  console.error(error);
}

export default function App() {
  return (
    <ConvivaNavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
      </Tab.Navigator>
    </ConvivaNavigationContainer>
  );
}
```

#### React Navigation < 5

Wrap the `AppNavigator` (result of `createAppContainer()`) with `withReactNavigationAutotrack`:

```js
import { createStackNavigator, createAppContainer } from 'react-navigation';
import {
  withReactNavigationAutotrack,
  autocaptureNavigationTrack,
} from '@convivainc/conviva-react-native-appanalytics';

const AppNavigator = createAppContainer(
  createStackNavigator(
    { Home: HomeScreen, Settings: SettingsScreen },
    { initialRouteName: 'Home' }
  )
);

let App;
try {
  App = withReactNavigationAutotrack(autocaptureNavigationTrack)(AppNavigator);
  if (!App) {
    console.error('Navigation app setup returned null');
  }
} catch (error) {
  console.error(error);
}
export default App;
```

---

## More Features

### Set the User ID (Viewer ID)

User ID is a unique string identifier to distinguish individual viewers. If using Conviva Video Sensor, match it with the Viewer ID. Use a non-PII identifier only (opaque provider UID, stored UUID, or backend account ID - never email or phone).

```js
try {
  if (tracker != null) {
    tracker.setSubjectData({ userId: 'your-non-pii-user-id' });
  }
} catch (error) {
  console.error(error);
}
```

Clear on logout:
```js
try {
  if (tracker != null) {
    tracker.setSubjectData({ userId: null });
  }
} catch (error) {
  console.error(error);
}
```

### Track Custom Events

Use `trackCustomEvent()` to track application-specific events.

| Parameter | Type | Description |
|---|---|---|
| `eventName` | `string` | Name of the custom event (mandatory) |
| `eventData` | `object` | Any JSON-serializable object |

```js
try {
  if (tracker != null) {
    tracker.trackCustomEvent('custom_event_name', {
      tagKey1: 'tagValue1',
      tagKey2: 100,
      tagKey3: true,
    });
  }
} catch (error) {
  console.error(error);
}
```

### Track Revenue Events (>= 0.2.8)

Use `trackRevenueEvent()` to track purchase and revenue events.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `totalOrderAmount` | `number` | Yes | Total order amount |
| `transactionId` | `string` | Yes | Unique transaction identifier |
| `currency` | `string` | Yes | Currency code (e.g. `"USD"`) |
| `taxAmount` | `number` | No | Tax amount |
| `shippingCost` | `number` | No | Shipping cost |
| `discount` | `number` | No | Order-level discount amount |
| `cartSize` | `number` | No | Number of items in the cart |
| `paymentMethod` | `string` | No | Payment method used |
| `paymentProvider` | `string` | No | Payment provider name |
| `items` | `RevenueEventItemProps[]` | No | Array of purchased items |
| `extraMetadata` | `object` | No | Any additional key-value pairs |

Each item in `items` may include: `productId`, `name`, `sku`, `category`, `unitPrice`, `quantity`, `discount`, `brand`, `variant`, `extraMetadata`.

```js
try {
  if (tracker != null) {
    tracker.trackRevenueEvent({
      totalOrderAmount: 49.99,
      transactionId: 'txn-001',
      currency: 'USD',
      taxAmount: 4.50,
      shippingCost: 5.99,
      paymentMethod: 'credit_card',
      items: [
        {
          productId: 'prod-123',
          name: 'Widget',
          unitPrice: 19.99,
          quantity: 2,
        },
      ],
    });
  }
} catch (error) {
  console.error(error);
}
```

### Set / Clear Custom Tags

Custom tags are global key-value pairs attached to all subsequent events until cleared.

**Set tags:**
```js
try {
  if (tracker != null) {
    tracker.setCustomTags({
      tagKey1: 'tagValue1',
      tagKey2: 100,
      tagKey3: true,
    });
  }
} catch (error) {
  console.error(error);
}
```

**Set tags with category:**
```js
try {
  if (tracker != null) {
    tracker.setCustomTagsWithCategory('myCategory', {
      tagKey1: 'tagValue1',
    });
  }
} catch (error) {
  console.error(error);
}
```

**Clear specific tags:**
```js
try {
  if (tracker != null) {
    tracker.clearCustomTags(['tagKey1', 'tagKey2']);
  }
} catch (error) {
  console.error(error);
}
```

**Clear all tags:**
```js
try {
  if (tracker != null) {
    tracker.clearAllCustomTags();
  }
} catch (error) {
  console.error(error);
}
```

### Track Page View Events

Use `trackPageView()` to track in-app page navigations explicitly.

```js
try {
  if (tracker != null) {
    tracker.trackPageView({
      pageUrl: 'https://example.com/home',
      pageTitle: 'Home',    // optional
      referrer: 'https://example.com', // optional
    });
  }
} catch (error) {
  console.error(error);
}
```

### WebView Event Bridge

To track events from web content rendered in `react-native-webview`:

```js
import { getWebViewCallback } from '@convivainc/conviva-react-native-appanalytics';
import { WebView } from 'react-native-webview';

let webViewCallback;
try {
  webViewCallback = getWebViewCallback();
  if (!webViewCallback) {
    console.error('WebView callback setup returned null');
  }
} catch (error) {
  console.error(error);
}

<WebView
  source={{ uri: 'https://your-web-app.com' }}
  onMessage={webViewCallback}
/>
```

The web app must use the Conviva WebView tracker to send events.

### WebView Client ID Sync

> Available from React Native SDK [v0.4.0](https://github.com/Conviva/conviva-react-native-appanalytics/releases/tag/v0.4.0). Requires React Native 0.68+, [`react-native-webview`](https://github.com/react-native-webview/react-native-webview) v11+, and Android plugin [v0.3.9](https://github.com/Conviva/conviva-android-plugin/releases/tag/v0.3.9)+. JavaScript must be enabled in the WebView for this feature to work.

The SDK automatically shares the native client ID with in-app WebViews, linking native and web sessions to the same user. It uses two mechanisms:

- **Cookie (primary):** Seeds a `Conviva_sdkConfig` cookie into the WebView cookie jar per configured domain.
- **JS bridge (fallback):** Web SDK reads the native client ID from the injected bridge when the cookie is unavailable.

**Web SDK compatibility:** The cookie path works with any Web SDK version. The JS bridge fallback requires **Web SDK ≥ [2.2.0](https://github.com/Conviva/conviva-js-appanalytics/releases/tag/v2.2.0)**.

#### Integration Options

**Option 1 — Remote config only (no code changes required):** Both cookie seeding and JS bridge are enabled by default. Contact Conviva support to configure domains in remote config for your account.

**Option 2 — Supply fallback domains in app code:**

Pass a `clidSyncConfig` object as the third argument to `createTracker()`. App-config domains take effect immediately before the first remote config fetch; once remote config is received, its domain list replaces the app-config list.

**JavaScript:**
```js
import { createTracker } from '@convivainc/conviva-react-native-appanalytics';

let tracker;
try {
  tracker = createTracker('YOUR_CUSTOMER_KEY', 'YOUR_APP_NAME', {
    clidSyncConfig: {
      webViewCookie: {
        domains: ['.example.com', '.partner.com'], // use leading-dot for subdomain coverage
      }
    },
  });
} catch (error) {
  console.error(error);
}
```

**TypeScript:**
```ts
import { createTracker, ReactNativeTracker } from '@convivainc/conviva-react-native-appanalytics';

let tracker: ReactNativeTracker | undefined;
try {
  tracker = createTracker('YOUR_CUSTOMER_KEY', 'YOUR_APP_NAME', {
    clidSyncConfig: {
      webViewCookie: {
        domains: ['.example.com', '.partner.com'], // use leading-dot for subdomain coverage
      }
    },
  });
} catch (error) {
  console.error(error);
}
```

> Use leading-dot domains (`.example.com`) to cover all subdomains. Domains without a leading dot match only the exact host.

| Option | Type | Description |
|---|---|---|
| `webViewCookie.domains` | `string[]` | Domains that receive the `Conviva_sdkConfig` cookie. Use leading-dot form (`.example.com`). |


### Client ID

```js
import { getClientId, setClientId } from '@convivainc/conviva-react-native-appanalytics';

try {
  const id = await getClientId();
  if (id == null) {
    console.error('getClientId returned null');
  }
  await setClientId('custom-client-id');
} catch (error) {
  console.error(error);
}
```

### Error Tracking

> Available from React Native SDK v0.5.0.

The SDK captures JavaScript errors automatically once `createTracker(...)` runs — **no extra code is required**. The following are captured out of the box:

- **Uncaught errors** thrown anywhere in your JS (via a chained global error handler).
- **Unhandled promise rejections** (promises rejected with no `.catch()`).
- **Native fatal crashes**, deduplicated against the JS error stream.

Rate limiting is enabled by default to protect against error storms.

Error tracking is **on by default**. To disable it entirely, pass `errorTracking: false` as the third argument to `createTracker`: or via conviva remote config

```js
import { createTracker } from '@convivainc/conviva-react-native-appanalytics';

const tracker = createTracker('YOUR_CUSTOMER_KEY', 'YOUR_APP_NAME', {
  errorTracking: false, // fully disable JS error capture
});
```

#### Configuration Options

Pass an `errorTracking` object to `createTracker` to customize capture. Every field is optional.

| Option | Type | Default | Description |
|---|---|---|---|
| `enabled` | `boolean` | `true` | Master switch for the error tracking module. |
| `captureGlobalErrors` | `boolean` | `true` | Capture uncaught errors via the global handler. |
| `captureUnhandledRejections` | `boolean` | `true` | Capture unhandled promise rejections. |
| `suppressInDev` | `boolean` | `false` | Skip capture while running in dev mode (`__DEV__`). |
| `enableRateLimiting` | `boolean` | `true` | Drop events once the per-window limit is exceeded. |
| `maxEventsPerWindow` | `number` | `20` | Max events captured per rate-limit window. |
| `rateLimitWindowMs` | `number` | `1000` | Rate-limit window length, in milliseconds. |
| `disconnectDurationMs` | `number` | `2000` | Cool-down after the limit is hit, in milliseconds. |
| `promiseRejectionsAsHandled` | `boolean` | `false` | Report unhandled rejections as handled (`warning`) instead of unhandled (`error`). |
| `bundleId` | `string` | — | JS bundle hash for symbolication of OTA-updated apps. |
| `beforeCapture` | `(payload) => boolean \| void` | — | Hook to enrich or filter each event. Return `false` to drop it. |

```js
const tracker = createTracker('YOUR_CUSTOMER_KEY', 'YOUR_APP_NAME', {
  errorTracking: {
    suppressInDev: true,
    maxEventsPerWindow: 10,
    beforeCapture: (payload) => {
      // Drop noisy errors, or attach extra context before dispatch.
      if (payload.message.includes('Network request failed')) {
        return false; // suppress this event
      }
    },
  },
});
```

#### Capture Render-phase Errors with `ConvivaErrorBoundary`

Errors thrown during a component's render are not caught by the global handler. Wrap any part of your tree in `ConvivaErrorBoundary` to capture those errors and render a fallback UI(optional).

```jsx
import { ConvivaErrorBoundary } from '@convivainc/conviva-react-native-appanalytics';

<ConvivaErrorBoundary
  name="CheckoutScreen"
  fallback={({ error, reset }) => (
    <View>
      <Text>Something went wrong: {String(error && error.message)}</Text>
      <Button title="Try again" onPress={reset} />
    </View>
  )}
>
  <CheckoutScreen />
</ConvivaErrorBoundary>
```

| Prop | Type | Description |
|---|---|---|
| `children` | `ReactNode` | The subtree to protect. |
| `fallback` | `ReactNode` or `({ error, reset }) => ReactNode` | What to render after an error is caught. |
| `name` | `string` | Human-readable label attached to the captured error. |
| `resetKeys` | `unknown[]` | When any value changes, the boundary resets and re-renders `children`. |
| `onError` | `(error, componentStack) => void` | Optional callback invoked when an error is caught. Must not throw. |

#### Report Errors Manually with `trackError`

Use `trackError` inside a `try/catch` to report errors you handle yourself. `message` is required; all other fields are optional.

```js
import { trackError } from '@convivainc/conviva-react-native-appanalytics';

try {
  await riskyOperation();
} catch (error) {
  try {
    await trackError({
      message: error.message,
      errorType: error.name,
      stackTrace: error.stack,
      isFatal: false,
      isHandled: true,
      attributes: { feature: 'checkout', step: 'payment' },
    });
  } catch (e) {
    console.error(e);
  }
}
```

`trackError` is also available on the tracker instance as `tracker.trackError({ ... })`.

#### Attach Custom Attributes to Every Error

Use the `errorTracker` singleton to attach attributes that should appear on all subsequently captured errors (for example, app build or environment). Attributes persist until removed.

```js
import { errorTracker } from '@convivainc/conviva-react-native-appanalytics';

try {
  errorTracker.addAttribute('appBuild', '2026.6.1');
  errorTracker.addAttribute('environment', 'production');
  // Remove when no longer relevant:
  errorTracker.removeAttribute('environment');
} catch (error) {
  console.error(error);
}
```

`errorTracker` also exposes `setEnabled(boolean)` to toggle capture at runtime and `setRateLimitingEnabled(boolean)` to toggle rate limiting.

#### Symbolication

Minified, production stack traces are symbolicated automatically by Conviva's backend — no source-map upload step is required in your build.
Note: For apps that ship JS via OTA updates, supply a `bundleId` in the `errorTracking` config so the backend can match the running bundle to its source maps.

---

## Auto-collected Events

Conviva automatically collects a rich set of app performance metrics after completing the Quick Start.

| Event | Occurrence | Requirements |
|---|---|---|
| `network_request` | After receiving a network request response | Android: requires android-plugin; iOS: auto-collected |
| `screen_view` | When a screen is interacted with on first launch or relaunch | Native sensors + Conviva instrumentation plugin + navigation container wrapping |
| `application_error` | When an unhandled error occurs in the application, including uncaught JavaScript errors and unhandled promise rejections | Auto-collected from native sensors; JS errors captured by the [Error Tracking](#error-tracking) module |
| `button_click` | On button click callback | Native sensors + Conviva instrumentation babel plugin |
| `application_background` | When the app moves to the background | Auto-collected from native sensors |
| `application_foreground` | When the app moves to the foreground | Auto-collected from native sensors |
| `application_install` | When the app is launched for the first time after install | Auto-collected from native sensors |

### Validation

To verify the integration for auto-collected events, check the [validation dashboard](https://pulse.conviva.com/app/appmanager/ecoIntegration/validation) _(Conviva login required)_.

---

## FAQ

[DPI Integration FAQ](https://pulse.conviva.com/learning-center/content/sensor_developer_center/tools/eco_integration/eco_integration_faq.htm)
