npm package: @kalporg/sniffurl
Description: SniffURL React Native SDK for visitor tracking and analytics
Author: Kalp Labs
Latest version: 1.0.17

# SniffURL React Native SDK

Track user events, identify visitors, and analyze user behavior in your React Native applications.

## Installation

```bash
npm install @kalporg/sniffurl @react-native-async-storage/async-storage
```

Or with yarn:

```bash
yarn add @kalporg/sniffurl @react-native-async-storage/async-storage
```

### iOS Setup

```bash
cd ios && pod install && cd ..
```

## Features

✅ **Automatic Visitor ID Generation** - Every user gets a unique, persistent visitor ID (even without campaigns)  
✅ **Real-Time Presence Tracking** - Shows live mobile app users in dashboard  
✅ **Event Tracking** - Track installs, signups, purchases, and custom events  
✅ **User Identification** - Link events to specific users  
✅ **Deep Link Support** - Track campaign attribution  
✅ **Battery Efficient** - Smart heartbeat with AppState handling  
✅ **Cross-Platform** - Works on iOS and Android  
✅ **Persistent Storage** - Visitor ID survives app restarts  

## Quick Start

```javascript
import { useEffect } from "react";
import { AppState } from "react-native";
import { SniffURL } from "@kalporg/sniffurl";

export default function App() {
  useEffect(() => {
    const initSDK = async () => {
      // Initialize SDK (auto-starts real-time presence tracking)
      await SniffURL.init({
        projectKey: "your_project_key",
        apiKey: "sk_live_your_api_key"
      });

      // Track app open
      await SniffURL.trackEvent("app_open");
    };

    initSDK();

    // Optional: Handle app state for battery optimization
    const subscription = AppState.addEventListener('change', nextAppState => {
      if (nextAppState === 'active') {
        SniffURL.startPresenceTracking(); // Resume when app active
      } else {
        SniffURL.stopPresenceTracking(); // Pause when app backgrounded
      }
    });

    return () => {
      subscription?.remove();
      SniffURL.stopPresenceTracking();
    };
  }, []);

  return <YourApp />;
}
```

## Configuration

### Option 1: Simple Init

```javascript
SniffURL.init({
  projectKey: "your_project_key",
  apiKey: "sk_live_your_api_key"
});
```

### Option 2: Advanced Configuration

```javascript
SniffURL.configure({
  projectKey: "your_project_key",
  apiKey: "sk_live_your_api_key",
  enableAutoTracking: true,        // auto-track app_open
  debug: __DEV__                   // enable debug logs
});
```

## Tracking Events

### Basic Event Tracking

```javascript
// Track install
SniffURL.trackEvent("install");

// Track signup
SniffURL.trackEvent("signup", { 
  userId: "U123", 
  plan: "basic" 
});

// Track purchase
SniffURL.trackEvent("purchase", {
  orderId: "ORD-998877",
  amount: 1499,
  currency: "INR"
});

// Track custom events
SniffURL.trackEvent("level_up", { 
  level: 7, 
  character: "wizard" 
});
```

### Screen Tracking

```javascript
SniffURL.trackScreen("Product Details", {
  product_id: "123",
  category: "Electronics"
});
```

## User Identification

Identify users after login. Once identified, user details are automatically included in all subsequent events:

```javascript
// Identify user (stores info locally)
await SniffURL.identify({
  userId: "user123",
  email: "user@example.com",
  name: "John Doe",
  phone: "+1234567890"
});

// All future events will include user details automatically
await SniffURL.trackEvent("purchase", { amount: 99.99 });
// This event will include: userId, email, name, phone + purchase data
```

**Important:** 
- Call `identify()` early (after login/signup)
- User details persist across app restarts
- All tracked events will include the identified user info

## Real-Time Presence Tracking

The SDK automatically sends heartbeat signals every 30 seconds to track live app users. This allows the dashboard to show how many users are currently active in your mobile app.

### Automatic Tracking

Heartbeat tracking starts automatically when you call `init()` or `configure()`:

```javascript
await SniffURL.init({
  projectKey: "your_project_key",
  apiKey: "sk_live_your_api_key"
});
// 💓 Heartbeat automatically started!
```

### Battery Optimization

For better battery life, pause/resume heartbeat based on app state:

```javascript
import { AppState } from "react-native";

const subscription = AppState.addEventListener('change', nextAppState => {
  if (nextAppState === 'active') {
    SniffURL.startPresenceTracking(); // Resume when foreground
  } else {
    SniffURL.stopPresenceTracking(); // Pause when background
  }
});
```

### Manual Control

```javascript
// Start presence tracking
SniffURL.startPresenceTracking();

// Stop presence tracking
SniffURL.stopPresenceTracking();
```

### Dashboard View

In your SniffURL dashboard:
- **Real-time Users** widget shows live mobile app users
- **Platform breakdown**: 📱 Mobile App: X | 🖥️ Website: Y
- Updates every 30 seconds automatically

## Deep Link Tracking

The SDK automatically handles deep links with `sn_vid` parameter to track visitor attribution:

```
yourapp://campaign?sn_vid=visitor_hash_123
```

### Manual Deep Link Handling

```javascript
import { SniffURL } from "@kalporg/sniffurl";

// Handle custom deep link
SniffURL.handleUrl("yourapp://promo?sn_vid=abc123");
```

## API Reference

### SniffURL.init(options)
Initialize the SDK.

**Options:**
- `projectKey` (string, required): Your project key (40 characters)
- `apiKey` (string, required): Your API key

### SniffURL.configure(options)
Advanced initialization with auto-tracking.

**Options:**
- `projectKey` (string, required): Your project key (40 characters)
- `apiKey` (string, required): Your API key
- `enableAutoTracking` (boolean, default: true): Auto-track app_open
- `debug` (boolean, default: false): Enable debug logs

### SniffURL.trackEvent(event, data)
Track a custom event.

**Parameters:**
- `event` (string): Event name
- `data` (object, optional): Event properties

### SniffURL.identify(userData)
Identify a user.

**Parameters:**
- `userData` (object): User properties (userId, email, name, etc.)

### SniffURL.trackScreen(screenName, properties)
Track a screen view.

**Parameters:**
- `screenName` (string): Screen name
- `properties` (object, optional): Screen properties

### SniffURL.getVisitorId()
Get the current visitor ID.

**Returns:** Promise<string>

### SniffURL.startPresenceTracking()
Start real-time presence tracking (heartbeat every 30s).

**Note:** Auto-started by `init()` and `configure()`

### SniffURL.stopPresenceTracking()
Stop real-time presence tracking to save battery.

**Note:** Call this when app goes to background

## Example

```javascript
import React, { useEffect } from "react";
import { SniffURL } from "@kalporg/sniffurl";

export default function App() {
  useEffect(() => {
    const initSDK = async () => {
      // 1. Initialize SDK
      await SniffURL.configure({
        projectKey: "kalp_12345",
        apiKey: "sk_live_abcde",
        projectKey: "your_project_key",
        enableAutoTracking: true,
        debug: __DEV__
      });

      // 2. Track install (first time)
      await SniffURL.trackEvent("install");
    };

    initSDK();
  }, []);

  const handleSignup = async (userData) => {
    // 1. Identify user first (persists locally)
    await SniffURL.identify({
      userId: userData.id,
      email: userData.email,
      name: userData.name,
      phone: userData.phone
    });

    // 2. Track signup (user details automatically included)
    await SniffURL.trackEvent("signup", {
      plan: userData.plan
    });
  };

  const handlePurchase = async (order) => {
    // User details automatically included if identified
    await SniffURL.trackEvent("purchase", {
      orderId: order.id,
      amount: order.amount,
      currency: order.currency
    });
  };

  return <YourApp onSignup={handleSignup} onPurchase={handlePurchase} />;
}
```

**Note:** Visitor ID is automatically generated and persisted. User details from `identify()` are stored locally and included in all future events automatically.

## Testing with CURL

You can test the tracking API directly:

```bash
curl --location 'https://api.sniffurl.com/api/embed/track' \
--header 'Content-Type: application/json' \
--header 'x-project-id: YOUR_PROJECT_KEY' \
--header 'x-api-key: YOUR_API_KEY' \
--data '{
  "event": "generate_lead",
  "sn_vid": "v_your_visitor_id",
  "page_url": "https://yourapp.com/pricing",
  "device_type": "mobile",
  "campaign_source": "meta",
  "lead_stage": "form_submit"
}'
```

**Note:** Use `x-project-id` with your **Project Key** (40 characters), not the MongoDB ObjectId.

## Troubleshooting

### BSON ObjectId Error
If you see: `Argument passed in must be a string of 24 hex characters`

**Solution:** Make sure you're using the **Project Key** (from API Keys page) in the `x-project-id` header, not the MongoDB project ID.

## License

MIT © Kalp Labs