npm package: @openmobile/react-native
Description: OpenMobile React Native SDK - Simple Tags for behavioral analytics
Author: OpenMobile Team
Latest version: 0.2.0

# OpenMobile React Native SDK

Simple Tags for Behavioral Analytics - React Native implementation.

## Features

- **4-line integration** - Get started in under 5 minutes
- **Privacy-first** - SHA-256 hashing for user IDs and emails
- **Offline support** - Events are queued and synced when online
- **Automatic batching** - Efficient network usage with configurable flush intervals
- **Session management** - 30-minute session timeout with automatic renewal
- **React hooks** - Easy screen tracking with `useOpenMobileScreen`
- **TypeScript** - Full type safety and IntelliSense support

## Installation

```bash
npm install @openmobile/react-native @react-native-async-storage/async-storage expo-crypto
```

Or with Yarn:

```bash
yarn add @openmobile/react-native @react-native-async-storage/async-storage expo-crypto
```

### Expo

If you're using Expo, install the dependencies:

```bash
npx expo install @react-native-async-storage/async-storage expo-crypto
```

### React Native CLI

For React Native CLI projects, you'll need to install the native dependencies:

```bash
npm install @react-native-async-storage/async-storage
cd ios && pod install
```

## Quick Start

### 1. Initialize the SDK

In your app's entry point (usually `App.tsx` or `index.js`):

```typescript
import { OpenMobile } from '@openmobile/react-native'

// Initialize before your app renders
OpenMobile.init({
  apiKey: 'pk_your_api_key_here',
  debug: __DEV__, // Enable debug logging in development
})
```

### 2. Identify Users

After successful login:

```typescript
OpenMobile.identify('user_123', {
  email: 'user@example.com', // Will be hashed
  plan: 'premium',
  name: 'John Doe',
})
```

### 3. Track Screens

**Option A: Using the React hook (recommended)**

```typescript
import { useOpenMobileScreen } from '@openmobile/react-native'

function CheckoutScreen() {
  useOpenMobileScreen('checkout', { currency: 'USD' })

  return <View>{/* Your screen content */}</View>
}
```

**Option B: Manual tracking**

```typescript
OpenMobile.screen('checkout', { currency: 'USD' })
```

### 4. Track Events

```typescript
OpenMobile.track('purchase_complete', {
  value: 99.99,
  currency: 'USD',
  items: 3,
})
```

### 5. Logout

On user logout:

```typescript
OpenMobile.reset()
```

## API Reference

### `init(config: OpenMobileConfig)`

Initialize the SDK. Must be called once before any other method.

**Parameters:**

- `apiKey` (required): Your OpenMobile API key from the dashboard
- `debug` (optional): Enable debug logging. Default: `false`
- `flushInterval` (optional): Auto-flush interval in ms. Default: `10000` (10s)
- `maxBatchSize` (optional): Max events per batch. Default: `100`
- `trackScreenDuration` (optional): Auto-track screen durations. Default: `true`
- `maxOfflineEvents` (optional): Max events to store offline. Default: `1000`
- `apiHost` (optional): Custom API endpoint. Default: `https://api.openmobile.io`

**Example:**

```typescript
OpenMobile.init({
  apiKey: 'pk_your_api_key_here',
  debug: true,
  flushInterval: 15000, // 15 seconds
  maxBatchSize: 50,
})
```

### `identify(userId: string, traits?: UserTraits)`

Identify the current user. Call after successful login.

**Note:** `userId` and `email` are automatically hashed (SHA-256) before sending.

**Parameters:**

- `userId` (required): Unique user identifier (will be hashed)
- `traits` (optional): User attributes (max 20 keys)

**Example:**

```typescript
OpenMobile.identify('user_123', {
  email: 'user@example.com',
  name: 'John Doe',
  plan: 'premium',
  created_at: '2024-01-15',
})
```

### `screen(screenName: string, properties?: EventProperties)`

Track a screen view.

**Parameters:**

- `screenName` (required): Screen name (1-255 characters)
- `properties` (optional): Additional data (max 50 keys)

**Example:**

```typescript
OpenMobile.screen('product_detail', {
  product_id: '12345',
  category: 'electronics',
})
```

### `track(eventName: string, properties?: EventProperties)`

Track a custom event.

**Parameters:**

- `eventName` (required): Event name (1-255 characters)
- `properties` (optional): Additional data (max 50 keys)

**Example:**

```typescript
OpenMobile.track('add_to_cart', {
  product_id: '12345',
  price: 29.99,
  quantity: 2,
})
```

### `reset()`

Clear user identity and start a new session. Call on logout.

**Example:**

```typescript
const handleLogout = async () => {
  await logout() // Your logout logic
  OpenMobile.reset()
}
```

### `flush()`

Manually flush pending events to the server. Useful before app termination.

**Returns:** `Promise<void>`

**Example:**

```typescript
await OpenMobile.flush()
```

### `useOpenMobileScreen(screenName: string, properties?: EventProperties)`

React hook to automatically track screen views with duration.

**Example:**

```typescript
function ProductDetailScreen({ productId }) {
  useOpenMobileScreen('product_detail', { product_id: productId })

  return <View>{/* Screen content */}</View>
}
```

## Complete Example

```typescript
import React, { useEffect } from 'react'
import { View, Button, Text } from 'react-native'
import { OpenMobile, useOpenMobileScreen } from '@openmobile/react-native'

// Initialize once at app start
OpenMobile.init({
  apiKey: 'pk_your_api_key_here',
  debug: __DEV__,
})

function LoginScreen({ onLogin }) {
  useOpenMobileScreen('login')

  const handleLogin = (user) => {
    OpenMobile.identify(user.id, {
      email: user.email,
      name: user.name,
      plan: user.plan,
    })
    onLogin()
  }

  return (
    <View>
      <Button title="Login" onPress={() => handleLogin({ id: '123', email: 'user@example.com' })} />
    </View>
  )
}

function CheckoutScreen() {
  useOpenMobileScreen('checkout')

  const handlePurchase = () => {
    OpenMobile.track('purchase_complete', {
      value: 99.99,
      currency: 'USD',
    })
  }

  return (
    <View>
      <Button title="Complete Purchase" onPress={handlePurchase} />
    </View>
  )
}

function ProfileScreen({ onLogout }) {
  useOpenMobileScreen('profile')

  const handleLogout = () => {
    OpenMobile.reset()
    onLogout()
  }

  return (
    <View>
      <Button title="Logout" onPress={handleLogout} />
    </View>
  )
}
```

## Privacy & Security

### Data Hashing

- **User IDs**: Hashed with SHA-256 before storage/transmission
- **Emails**: Normalized (lowercase, trimmed) and hashed with SHA-256
- **Original values never leave the device**

### Offline Support

- Events are persisted to AsyncStorage
- Automatic retry with exponential backoff
- Max 1000 events stored offline (configurable)

### Session Management

- 30-minute session timeout
- Automatic session renewal on activity
- Sessions persist across app restarts (if < 30 min)

## Automatic Events

The SDK automatically tracks these events:

| Event              | Trigger                    | Properties                              |
| ------------------ | -------------------------- | --------------------------------------- |
| `session_start`    | SDK init or new session    | `{ session_count }`                     |
| `screen_duration`  | Navigate to another screen | `{ screen_name, duration_ms }`          |
| `app_backgrounded` | App goes to background     | `{ duration_in_foreground_ms }`         |
| `app_foregrounded` | App returns from background| `{ time_in_background_ms }`             |

## Error Handling

The SDK throws `OpenMobileError` for validation errors:

```typescript
import { OpenMobile, OpenMobileError, ErrorCode } from '@openmobile/react-native'

try {
  OpenMobile.track('invalid<script>event', {})
} catch (error) {
  if (error instanceof OpenMobileError) {
    console.error(`Error ${error.code}: ${error.message}`)
    // error.code === ErrorCode.XSS_DETECTED
  }
}
```

## Debugging

Enable debug mode to see SDK logs:

```typescript
OpenMobile.init({
  apiKey: 'pk_xxx',
  debug: true, // or __DEV__ for development only
})
```

Check SDK health:

```typescript
const health = OpenMobile.getHealth()
console.log(health)
// {
//   initialized: true,
//   sessionId: "uuid",
//   userId: "hashed_id",
//   pendingEvents: 5,
//   lastFlush: Date,
//   lastError: null,
//   offlineEventsCount: 0
// }
```

## Platform Requirements

- React Native 0.70+
- Expo SDK 49+
- iOS 14+
- Android API 24+ (Android 7.0)

## License

MIT

## Support

- Documentation: https://openmobile.io/docs
- Issues: https://github.com/openmobile/sdk-react-native/issues
- Email: support@openmobile.io