{"_id":"@axyle/expo-sdk","_rev":"5-e82726be27d225d58bebf8b9b1948434","name":"@axyle/expo-sdk","dist-tags":{"latest":"1.2.2"},"versions":{"1.0.0":{"name":"@axyle/expo-sdk","version":"1.0.0","keywords":["react-native","analytics","tracking"],"author":{"name":"Khushaal Choithramani"},"license":"MIT","_id":"@axyle/expo-sdk@1.0.0","maintainers":[{"name":"khushaal04","email":"khushaal.choithramani@gmail.com"}],"dist":{"shasum":"1fb646f9358a94e0d51222ef44cca292e8efcc08","tarball":"https://registry.npmjs.org/@axyle/expo-sdk/-/expo-sdk-1.0.0.tgz","fileCount":43,"integrity":"sha512-rA5aYyBrh3rITdxTuu/8rlhOwn9pRzTBc+bKPSAaMM2LIEDgd39UwAQcUO091lnXz57fnyt9ioTKKzXU/qrZ+Q==","signatures":[{"sig":"MEYCIQCYqqftphJ9rav9/goAo43yb77XgFuxsNEBCMvvTbyIaAIhAMrU4Ht706et+Wckdbd5+s6oxa+MWD2TzJFnLOUyikS6","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":121846},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"fa08b42780e542a17a2d5a7a42b745691bbf8652","scripts":{"build":"tsc","watch":"tsc --watch","prepack":"npm run build","prepublishOnly":"npm run build"},"_npmUser":{"name":"khushaal04","email":"khushaal.choithramani@gmail.com"},"_npmVersion":"10.9.2","description":"Axyle Analytics SDK for Expo and React Native applications","directories":{},"_nodeVersion":"23.11.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.3.3","@types/react":"^18.2.45","@types/react-native":"^0.72.8"},"peerDependencies":{"react":">=16.8.0","expo-device":"^5.0.0 || ^6.0.0","expo-router":"^6.0.0","react-native":">=0.60.0","expo-constants":"^15.0.0 || ^16.0.0","expo-application":"^5.0.0 || ^6.0.0","@react-native-async-storage/async-storage":"^1.19.0"},"peerDependenciesMeta":{"expo-router":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/expo-sdk_1.0.0_1769890953318_0.12045806962077976","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@axyle/expo-sdk","version":"1.1.0","keywords":["react-native","analytics","tracking"],"author":{"name":"Khushaal Choithramani"},"license":"MIT","_id":"@axyle/expo-sdk@1.1.0","maintainers":[{"name":"khushaal04","email":"khushaal.choithramani@gmail.com"}],"dist":{"shasum":"ac725f16bb5fdf2638ae16f310d5a28aaf882184","tarball":"https://registry.npmjs.org/@axyle/expo-sdk/-/expo-sdk-1.1.0.tgz","fileCount":43,"integrity":"sha512-cjpe3L5b5FqLLoG62eqKExH/JlKokTofxB2quZYltf1EAz5gq3yF0JNg6mjJgqiZ59NwItTkUKyyXWjxPURm+w==","signatures":[{"sig":"MEUCIQCR0hjZ33/CjnhKtUqWUTvjy9s/EPtTxWQJPfVKvaO/WwIgNTMgeuzNVKs9pPz9RvA0e6Czc0ObXnOB1ILSGey1Dj4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":129498},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"1bf81e00bd923caed990d94d630d5ab90c2590d5","scripts":{"build":"tsc","watch":"tsc --watch","prepack":"npm run build","prepublishOnly":"npm run build"},"_npmUser":{"name":"khushaal04","email":"khushaal.choithramani@gmail.com"},"_npmVersion":"10.9.2","description":"Axyle Analytics SDK for Expo and React Native applications","directories":{},"_nodeVersion":"23.11.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.3.3","@types/react":"^18.2.45","@types/react-native":"^0.72.8"},"peerDependencies":{"react":">=16.8.0","expo-device":"^5.0.0 || ^6.0.0","expo-router":"^6.0.0","react-native":">=0.60.0","expo-constants":"^15.0.0 || ^16.0.0","expo-application":"^5.0.0 || ^6.0.0","@react-native-async-storage/async-storage":"^1.19.0"},"peerDependenciesMeta":{"expo-router":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/expo-sdk_1.1.0_1769895276715_0.7854174221269443","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@axyle/expo-sdk","version":"1.2.0","keywords":["react-native","analytics","tracking"],"author":{"name":"Khushaal Choithramani"},"license":"MIT","_id":"@axyle/expo-sdk@1.2.0","maintainers":[{"name":"khushaal04","email":"khushaal.choithramani@gmail.com"}],"dist":{"shasum":"411a02cbd2eccecae892d0612ea1d9970bef2698","tarball":"https://registry.npmjs.org/@axyle/expo-sdk/-/expo-sdk-1.2.0.tgz","fileCount":41,"integrity":"sha512-WdBMeVAkbvE0NkGhGekyeOmqlJxWAetpYSqPzBMgq8CiCsgVlvo1phyMLVz0z8NRsqc1GY38LRl67TjTNpM9aQ==","signatures":[{"sig":"MEYCIQDJkzk89H4apn8NGr7op8Z4TTIHtQJXZOuv27UYnNx76QIhAKjtI9KqE0hgs4j/qcRdXZ/fqMQwDjfNe4/tzI4vRanW","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":126973},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"241aeba32ecf37a30a7ae3aec9ad596df7f7d474","scripts":{"build":"tsc","watch":"tsc --watch","prepack":"npm run build","prepublishOnly":"npm run build"},"_npmUser":{"name":"khushaal04","email":"khushaal.choithramani@gmail.com"},"_npmVersion":"11.8.0","description":"Axyle Analytics SDK for Expo and React Native applications","directories":{},"_nodeVersion":"24.13.1","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.3.3","@types/react":"^19.1.1"},"peerDependencies":{"react":">=16.8.0","expo-device":"^5.0.0 || ^6.0.0","expo-router":"^6.0.0","react-native":">=0.60.0","expo-constants":"^15.0.0 || ^16.0.0","expo-application":"^5.0.0 || ^6.0.0","@react-native-async-storage/async-storage":"^1.19.0"},"peerDependenciesMeta":{"expo-device":{"optional":true},"expo-router":{"optional":true},"expo-constants":{"optional":true},"expo-application":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/expo-sdk_1.2.0_1771146154779_0.42677734808358814","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"@axyle/expo-sdk","version":"1.2.1","keywords":["react-native","analytics","tracking"],"author":{"name":"Khushaal Choithramani"},"license":"MIT","_id":"@axyle/expo-sdk@1.2.1","maintainers":[{"name":"khushaal04","email":"khushaal.choithramani@gmail.com"}],"dist":{"shasum":"4c0807f48e05534edf1208564fe509b66e7ec748","tarball":"https://registry.npmjs.org/@axyle/expo-sdk/-/expo-sdk-1.2.1.tgz","fileCount":41,"integrity":"sha512-MWlrvk/KUYQp2fWCNaDC/vgUnXK7cHSJ8X85t4AipOt2+o2+TUJwkKP75oI8s7WairRFZTkfABtQHDo9NTs1Sw==","signatures":[{"sig":"MEYCIQD7b2XuOlOEjNvq/12vSo1qHzuK7zPrAa+3oMfOP3S0vQIhAPyyS0mQL08P8L9W3HQmcKAZaacgrlO7c74oJYyulmgI","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":126957},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"241aeba32ecf37a30a7ae3aec9ad596df7f7d474","scripts":{"build":"tsc","watch":"tsc --watch","prepack":"npm run build","prepublishOnly":"npm run build"},"_npmUser":{"name":"khushaal04","email":"khushaal.choithramani@gmail.com"},"_npmVersion":"11.8.0","description":"Axyle Analytics SDK for Expo and React Native applications","directories":{},"_nodeVersion":"24.13.1","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.3.3","@types/react":"^19.1.1"},"peerDependencies":{"react":">=16.8.0","expo-device":"^5.0.0 || ^6.0.0","expo-router":"^6.0.0","react-native":">=0.60.0","expo-constants":"^15.0.0 || ^16.0.0","expo-application":"^5.0.0 || ^6.0.0","@react-native-async-storage/async-storage":"^1.19.0 || ^2.0.0"},"peerDependenciesMeta":{"expo-device":{"optional":true},"expo-router":{"optional":true},"expo-constants":{"optional":true},"expo-application":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/expo-sdk_1.2.1_1771228142200_0.08577123666952247","host":"s3://npm-registry-packages-npm-production"}},"1.2.2":{"name":"@axyle/expo-sdk","version":"1.2.2","description":"Axyle Analytics SDK for Expo and React Native applications","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","watch":"tsc --watch","prepublishOnly":"npm run build","prepack":"npm run build"},"keywords":["react-native","analytics","tracking"],"author":{"name":"Khushaal Choithramani"},"license":"MIT","peerDependencies":{"expo-application":">=5.0.0","expo-constants":">=15.0.0","expo-device":">=5.0.0","@react-native-async-storage/async-storage":">=1.19.0","react":">=16.8.0","react-native":">=0.60.0","expo-router":">=3.0.0"},"peerDependenciesMeta":{"expo-router":{"optional":true},"expo-application":{"optional":true},"expo-device":{"optional":true},"expo-constants":{"optional":true},"@react-native-async-storage/async-storage":{"optional":true}},"devDependencies":{"@types/react":"^19.1.1","typescript":"^5.3.3"},"gitHead":"241aeba32ecf37a30a7ae3aec9ad596df7f7d474","_id":"@axyle/expo-sdk@1.2.2","_nodeVersion":"24.13.1","_npmVersion":"11.8.0","dist":{"integrity":"sha512-IsS8A13ALIZdeoUcmnf1c6/8dXl9HzlVqYIinOQ0i1fiHnoVa6GJB2F8BfQQNJJp78EdcCger/LHaBIqP68oCg==","shasum":"2b9ef1aa8e3371b1436d20be7a9780336dd129d1","tarball":"https://registry.npmjs.org/@axyle/expo-sdk/-/expo-sdk-1.2.2.tgz","fileCount":41,"unpackedSize":127665,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCqvecoheAkPWcaEO0XCwzDgyQqF1eu3pTWlzQLYl+p6gIgMdlT/3VEHwvvtNVzQbfvfblqXeOZ2qhuI+gkA/60Euw="}]},"_npmUser":{"name":"khushaal04","email":"khushaal.choithramani@gmail.com"},"directories":{},"maintainers":[{"name":"khushaal04","email":"khushaal.choithramani@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/expo-sdk_1.2.2_1771228371050_0.7398679040013809"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-31T20:22:33.179Z","modified":"2026-02-16T07:52:51.330Z","1.0.0":"2026-01-31T20:22:33.465Z","1.1.0":"2026-01-31T21:34:36.876Z","1.2.0":"2026-02-15T09:02:35.000Z","1.2.1":"2026-02-16T07:49:02.359Z","1.2.2":"2026-02-16T07:52:51.186Z"},"author":{"name":"Khushaal Choithramani"},"license":"MIT","keywords":["react-native","analytics","tracking"],"description":"Axyle Analytics SDK for Expo and React Native applications","maintainers":[{"name":"khushaal04","email":"khushaal.choithramani@gmail.com"}],"readme":"# Axyle Analytics SDK\n\nA privacy-focused, lightweight analytics SDK for Expo and React Native applications.\n\n## Features\n\n- **[Simple Integration](#quick-start)** - One-line initialization with just an API key\n- **[Flexible User Identification](#user-identification)** - Set user ID at init time or during runtime with `identify()`\n- **[Automatic Tracking](#automatically-tracked-events)** - App lifecycle, sessions, and screen views\n- **[Offline Support](#quick-start)** - Events are queued and sent when connection is available\n- **[Privacy First](#privacy-methods)** - No PII collected by default, opt-out support, GDPR-compliant data deletion\n- **[Zero Configuration](#configuration)** - Sensible defaults for all settings\n- **[TypeScript Support](#typescript)** - Full type definitions included\n\n## Installation\n\n```bash\nnpx expo install @axyle/expo-sdk\n```\n\nThis automatically installs the required peer dependency (`@react-native-async-storage/async-storage`).\n\nFor richer device and app metadata (optional — requires a dev build):\n\n```bash\nnpx expo install expo-application expo-constants expo-device\n```\n\n### Expo Go Support\n\nThe SDK works out of the box with **Expo Go** — no dev build required. When running in Expo Go, the SDK gracefully falls back to default values for device and app metadata that require native modules (`expo-application`, `expo-device`, `expo-constants`). Core functionality like event tracking, session management, user identification, and offline queuing works exactly the same.\n\n| Data                              | Expo Go  | Dev Build   |\n| --------------------------------- | -------- | ----------- |\n| Event tracking                    | Full     | Full        |\n| Session management                | Full     | Full        |\n| User identification               | Full     | Full        |\n| Offline queuing                   | Full     | Full        |\n| OS, screen, locale, timezone      | Full     | Full        |\n| App name, version, build          | Defaults | Real values |\n| Device model, manufacturer, brand | Defaults | Real values |\n| Device type (phone/tablet)        | Defaults | Detected    |\n\n## Quick Start\n\n### 1. Initialize the SDK\n\nInitialize the SDK in your app's entry point (e.g., `App.tsx` or `_layout.tsx`):\n\n```tsx\nimport { useEffect } from \"react\";\nimport { Axyle } from \"@axyle/expo-sdk\";\n\nexport default function App() {\n  useEffect(() => {\n    Axyle.init(\"your-api-key\");\n  }, []);\n\n  return <YourApp />;\n}\n```\n\n**For pre-authenticated users** (already logged in before app loads):\n\n```tsx\nexport default function App() {\n  useEffect(async () => {\n    const user = await getLoggedInUser();\n    Axyle.init({\n      apiKey: \"your-api-key\",\n      userId: user?.id, // Optional: set user ID at init\n    });\n  }, []);\n\n  return <YourApp />;\n}\n```\n\n### 2. Track Custom Events\n\n```tsx\nimport { Axyle } from \"@axyle/expo-sdk\";\n\n// Track a button click\nAxyle.track(\"Button Clicked\", {\n  button: \"Sign Up\",\n  screen: \"Home\",\n});\n\n// Track a purchase\nAxyle.track(\"Purchase Completed\", {\n  amount: 29.99,\n  currency: \"USD\",\n  productId: \"premium-plan\",\n});\n```\n\n### 3. Identify Users\n\n```tsx\n// When user logs in\nAxyle.identify(\"user-123\", {\n  email: \"user@example.com\",\n  plan: \"premium\",\n});\n\n// When user logs out\nAxyle.reset();\n```\n\n## API Reference\n\n### Core Methods\n\n#### `Axyle.init(apiKey | config)`\n\nInitialize the SDK. Must be called before any other methods.\n\n```tsx\n// Pass API key as a string\nAxyle.init(\"your-api-key\");\n\n// Or as an object\nAxyle.init({ apiKey: \"your-api-key\" });\n\n// With optional user ID (for pre-authenticated users)\nAxyle.init({\n  apiKey: \"your-api-key\",\n  userId: \"user-123\",\n});\n```\n\n**Parameters:**\n\n- `apiKey` (string, required) - Your Axyle API key\n- `userId` (string, optional) - Set user ID at initialization\n\n#### `Axyle.track(eventName, properties?)`\n\nTrack a custom event with optional properties.\n\n```tsx\nAxyle.track(\"Video Watched\", {\n  videoId: \"abc123\",\n  duration: 120,\n  quality: \"HD\",\n});\n```\n\n**Property Types:** Properties must be primitives (string, number, boolean, null).\n\n#### `Axyle.identify(userId, traits?)`\n\nAssociate events with a user ID and optional traits.\n\n```tsx\nAxyle.identify(\"user-123\", {\n  email: \"user@example.com\",\n  plan: \"premium\",\n});\n```\n\n#### `Axyle.reset()`\n\nClear user data and start a new session. Call this on logout.\n\n```tsx\nAxyle.reset();\n```\n\n#### `Axyle.flush()`\n\nManually flush all queued events to the server.\n\n```tsx\nawait Axyle.flush();\n```\n\n#### `Axyle.shutdown()`\n\nGracefully shutdown the SDK (flushes events and cleans up resources).\n\n```tsx\nawait Axyle.shutdown();\n```\n\n### Privacy Methods\n\n#### `Axyle.optOut()`\n\nOpt out of tracking. Stops all event collection.\n\n```tsx\nAxyle.optOut();\n```\n\n#### `Axyle.optIn()`\n\nOpt back in to tracking.\n\n```tsx\nAxyle.optIn();\n```\n\n#### `Axyle.deleteUser(userId)`\n\nRequest deletion of user data (GDPR compliance).\n\n```tsx\nAxyle.deleteUser(\"user-123\");\n```\n\n### Analytics Methods\n\n#### `Axyle.getSessionStats()`\n\nGet current session statistics.\n\n```tsx\nconst stats = Axyle.getSessionStats();\n// { totalEvents: 15, eventsByType: { 'Button Clicked': 3, ... }, ... }\n```\n\n#### `Axyle.getSessionEvents()`\n\nGet all events in the current session.\n\n```tsx\nconst events = Axyle.getSessionEvents();\n```\n\n#### `Axyle.getEventsByType(eventName)`\n\nGet events filtered by type.\n\n```tsx\nconst buttonClicks = Axyle.getEventsByType(\"Button Clicked\");\n```\n\n## User Identification\n\nThe SDK offers flexible user identification that works with different authentication patterns. You can set a user ID at initialization time or dynamically during runtime.\n\n### Initialization with User ID\n\nSet the user ID during SDK initialization for pre-authenticated users:\n\n```tsx\nexport default function App() {\n  useEffect(async () => {\n    // Retrieve cached/stored user ID\n    const cachedUserId = await AsyncStorage.getItem(\"user_id\");\n\n    // Initialize with optional user ID\n    Axyle.init({\n      apiKey: \"your-api-key\",\n      userId: cachedUserId, // Optional: pre-authenticated user\n    });\n  }, []);\n\n  return <YourApp />;\n}\n```\n\n**When to use:**\n\n- User is already logged in when app starts\n- You have a cached/stored user ID from previous session\n- You want all events from app start to include user ID\n\n**Result:** All events immediately have the correct user ID.\n\n### Dynamic User Identification\n\nCall `identify()` when user logs in during app runtime:\n\n```tsx\nasync function handleLogin(username, password) {\n  const user = await login(username, password);\n\n  // Set user ID and associate with previous anonymous events\n  Axyle.identify(user.id, {\n    username: user.username,\n    email: user.email,\n    loginMethod: \"email\",\n  });\n}\n```\n\n**When to use:**\n\n- User starts anonymous and logs in later\n- You want to transition from anonymous to identified tracking\n- You need to capture user traits at login\n\n**Result:** Generates \"User Identified\" event with traits; previous anonymous events are associated with new user ID.\n\n### Comparing Init User ID vs identify()\n\n| Scenario                         | Init `userId`     | `identify()`                     |\n| -------------------------------- | ----------------- | -------------------------------- |\n| **Pre-authenticated users**      | ✅ Best choice    | Not needed                       |\n| **Users logging in mid-session** | ❌ Too early      | ✅ Use this                      |\n| **App restart with cached user** | ✅ Convenient     | Works but requires extra storage |\n| **Anonymous to identified flow** | ❌ Not applicable | ✅ Perfect                       |\n| **Traits/properties needed?**    | ❌ No (just ID)   | ✅ Yes (second param)            |\n| **Generates event?**             | ❌ No             | ✅ \"User Identified\"             |\n\n### Logout and Session Reset\n\nClear user data when user logs out:\n\n```tsx\nasync function handleLogout() {\n  // Flush any pending events\n  await Axyle.flush();\n\n  // Clear user ID and start new session\n  Axyle.reset();\n\n  // Optional: disable tracking if user requested it\n  // Axyle.optOut();\n}\n```\n\n**What `reset()` does:**\n\n- Clears the current user ID\n- Starts a new session with new session ID\n- Generates \"Session Started\" event for new session\n- Keeps anonymous ID for continuity\n\n### Complete Authentication Flow Example\n\n```tsx\nimport AsyncStorage from \"@react-native-async-storage/async-storage\";\nimport { Axyle } from \"@axyle/expo-sdk\";\n\nexport default function App() {\n  const [isInitialized, setIsInitialized] = useState(false);\n\n  useEffect(() => {\n    initializeAnalytics();\n  }, []);\n\n  const initializeAnalytics = async () => {\n    try {\n      // Try to restore user from previous session\n      const savedUserId = await AsyncStorage.getItem(\"user_id\");\n\n      Axyle.init({\n        apiKey: \"your-api-key\",\n        userId: savedUserId || undefined, // Set if available\n      });\n\n      setIsInitialized(true);\n    } catch (error) {\n      console.error(\"Analytics init failed:\", error);\n    }\n  };\n\n  const handleLogin = async (email, password) => {\n    const user = await authenticateUser(email, password);\n\n    // Save user ID for next app restart\n    await AsyncStorage.setItem(\"user_id\", user.id);\n\n    // Identify user in analytics\n    Axyle.identify(user.id, {\n      email: user.email,\n      name: user.name,\n    });\n  };\n\n  const handleLogout = async () => {\n    // Clear saved user ID\n    await AsyncStorage.removeItem(\"user_id\");\n\n    // Reset analytics\n    await Axyle.flush();\n    Axyle.reset();\n  };\n\n  return isInitialized ? <YourApp /> : <LoadingScreen />;\n}\n```\n\n## Screen Tracking\n\n### Manual Screen Tracking (Recommended)\n\n```tsx\nimport { useEffect } from \"react\";\nimport { trackScreen } from \"@axyle/expo-sdk\";\n\nexport default function HomeScreen() {\n  useEffect(() => {\n    trackScreen(\"Home\");\n  }, []);\n\n  return <View>...</View>;\n}\n\n// With additional properties\nexport default function ProductScreen({ productId }) {\n  useEffect(() => {\n    trackScreen(\"Product\", { productId });\n  }, [productId]);\n\n  return <View>...</View>;\n}\n```\n\n### Using the Screen Tracking Hook\n\n```tsx\nimport { useScreenTracking } from \"@axyle/expo-sdk\";\n\nfunction HomeScreen() {\n  useScreenTracking({\n    screenName: \"Home\",\n    properties: { section: \"main\" },\n    trackTime: true, // Track time spent on screen\n  });\n\n  return <View>...</View>;\n}\n```\n\n### React Navigation Integration\n\n```tsx\nimport { NavigationContainer } from \"@react-navigation/native\";\nimport { createNavigationTracker } from \"@axyle/expo-sdk\";\n\nconst navigationTracker = createNavigationTracker();\n\nfunction App() {\n  return (\n    <NavigationContainer onStateChange={navigationTracker}>\n      {/* Your navigators */}\n    </NavigationContainer>\n  );\n}\n```\n\n## Flow Tracking\n\nTrack multi-step user flows like onboarding, checkout, or tutorials:\n\n```tsx\nimport {\n  useFlowTracking,\n  trackFlowCompleted,\n  trackFlowAbandoned,\n} from \"@axyle/expo-sdk\";\n\n// In each step component\nfunction OnboardingStep1() {\n  useFlowTracking({\n    flowId: \"welcome-onboarding\",\n    flowType: \"onboarding\",\n    step: 1,\n    totalSteps: 4,\n    stepName: \"Welcome\",\n  });\n\n  return <View>...</View>;\n}\n\n// When flow completes\nfunction OnboardingComplete() {\n  useEffect(() => {\n    trackFlowCompleted(\"welcome-onboarding\", 4, { flowType: \"onboarding\" });\n  }, []);\n\n  return <View>...</View>;\n}\n\n// When user abandons flow (e.g., closes modal)\nconst handleClose = () => {\n  trackFlowAbandoned(\"welcome-onboarding\", currentStep, 4, {\n    flowType: \"onboarding\",\n    stepName: \"Current Step Name\",\n  });\n};\n```\n\n## Feature Tracking\n\nTrack feature usage and discovery:\n\n```tsx\nimport { trackFeatureUsage, useFeatureViewTracking } from \"@axyle/expo-sdk\";\n\n// Track when a feature is used\nconst handleShare = () => {\n  trackFeatureUsage(\"share\", { screen: \"Article\", method: \"button\" });\n  // ... share logic\n};\n\n// Track when a feature is viewed/discovered\nfunction NewFeatureBanner() {\n  useFeatureViewTracking(\"premium-upgrade-banner\", { location: \"home\" });\n\n  return <View>...</View>;\n}\n```\n\n## Scroll Tracking\n\nTrack scroll depth on content screens:\n\n```tsx\nimport { useScrollTracking, useWebScrollTracking } from \"@axyle/expo-sdk\";\n\n// React Native\nfunction ArticleScreen() {\n  const scrollViewRef = useScrollTracking({\n    screenName: \"Article\",\n    thresholds: [25, 50, 75, 100],\n  });\n\n  return <ScrollView ref={scrollViewRef}>{/* content */}</ScrollView>;\n}\n\n// Web\nfunction WebArticle() {\n  useWebScrollTracking({\n    screenName: \"Article\",\n    thresholds: [25, 50, 75, 100],\n  });\n\n  return <div>...</div>;\n}\n```\n\n## Automatically Tracked Events\n\nThe SDK automatically tracks:\n\n| Event              | Description                           |\n| ------------------ | ------------------------------------- |\n| `App Opened`       | App launches                          |\n| `App Backgrounded` | App goes to background                |\n| `App Foregrounded` | App returns to foreground             |\n| `Session Started`  | New session begins                    |\n| `Session Ended`    | Session expires (30 min inactivity)   |\n| `Screen Viewed`    | Screen navigation (with integrations) |\n\n## Event Schema\n\nEach event includes:\n\n```typescript\n{\n  id: string;              // Unique event ID\n  name: string;            // Event name\n  properties: object;      // Custom properties\n  timestamp: number;       // Unix timestamp (ms)\n  userId: string;          // User or anonymous ID\n  anonymousId: string;     // Persistent anonymous ID\n  sessionId: string;       // Current session ID\n  schemaVersion: string;   // Schema version\n  context: {\n    app: { name, version, build, namespace },\n    device: { id, manufacturer, model, name, type, brand },\n    os: { name, version },\n    screen: { width, height, density },\n    locale: string,\n    timezone: string,\n    environment: 'dev' | 'prod'\n  }\n}\n```\n\n## Configuration\n\nThe SDK uses sensible defaults:\n\n| Setting         | Default    | Description                     |\n| --------------- | ---------- | ------------------------------- |\n| Queue Size      | 100 events | Max events before auto-flush    |\n| Flush Interval  | 10 seconds | Auto-flush interval             |\n| Session Timeout | 30 minutes | Inactivity timeout for sessions |\n| Retry Attempts  | 3          | Network retry attempts          |\n| Batch Size      | 500 KB     | Max batch size                  |\n\nThese settings are optimized for mobile and cannot be overridden.\n\n## Best Practices\n\n### 1. Initialize Early\n\nInitialize in your root component before rendering any screens:\n\n```tsx\nfunction App() {\n  useEffect(() => {\n    Axyle.init(\"your-api-key\");\n  }, []);\n\n  return <YourApp />;\n}\n```\n\n### 2. Handle User ID Correctly\n\n**For pre-authenticated apps:**\n\n```tsx\nuseEffect(() => {\n  (async () => {\n    const userId = await getStoredUserId();\n    Axyle.init({\n      apiKey: \"your-api-key\",\n      userId: userId,\n    });\n  })();\n}, []);\n```\n\n**For apps with login flow:**\n\n```tsx\n// Don't set user ID at init\nAxyle.init(\"your-api-key\");\n\n// Set it when user logs in\nconst handleLogin = (user) => {\n  Axyle.identify(user.id, { email: user.email });\n};\n```\n\n**Always flush before logout:**\n\n```tsx\nconst handleLogout = async () => {\n  await Axyle.flush(); // Ensure all events sent\n  Axyle.reset();\n};\n```\n\n### 3. Use Descriptive Event Names\n\n```tsx\n// Good\nAxyle.track('Checkout Completed', { ... });\nAxyle.track('Profile Photo Updated', { ... });\n\n// Avoid\nAxyle.track('click', { ... });\nAxyle.track('event1', { ... });\n```\n\n### 3. Keep Properties Simple\n\nUse primitive types for properties:\n\n```tsx\n// Good\nAxyle.track(\"Item Added\", {\n  itemId: \"123\",\n  price: 29.99,\n  quantity: 2,\n});\n\n// Avoid nested objects\n```\n\n### 4. Flush Before Critical Actions\n\n```tsx\nasync function logout() {\n  await Axyle.flush();\n  Axyle.reset();\n  // ... logout logic\n}\n```\n\n### 5. Respect User Privacy\n\n```tsx\nfunction SettingsScreen() {\n  const [optedOut, setOptedOut] = useState(false);\n\n  const handleOptOut = async () => {\n    if (optedOut) {\n      await Axyle.optIn();\n    } else {\n      await Axyle.optOut();\n    }\n    setOptedOut(!optedOut);\n  };\n\n  return (\n    <View>\n      <Text>Analytics</Text>\n      <Switch value={!optedOut} onValueChange={handleOptOut} />\n    </View>\n  );\n}\n```\n\n## Troubleshooting\n\n### Events Not Sending\n\n1. Verify your API key is correct\n2. Check network connectivity\n3. Call `Axyle.flush()` to force send events\n4. Check if user has opted out\n\n### User ID Not Set\n\n**Issue:** Events don't have the expected user ID\n\n**Solutions:**\n\n- Verify `userId` is passed to `Axyle.init()` or set via `Axyle.identify()`\n- Check that `init()` is called before tracking events\n- Use `Axyle.getSessionStats()` to verify user ID in current session\n\n```tsx\nconst stats = Axyle.getSessionStats();\nconsole.log(\"Current user ID:\", stats?.userId); // Check if set correctly\n```\n\n### User ID Not Persisting Across App Restarts\n\n**Issue:** User ID is lost when app restarts\n\n**Solution:** Store and restore user ID from AsyncStorage\n\n```tsx\n// On login - save user ID\nAxyle.identify(userId, traits);\nawait AsyncStorage.setItem(\"user_id\", userId);\n\n// On app start - restore user ID\nconst savedUserId = await AsyncStorage.getItem(\"user_id\");\nAxyle.init({\n  apiKey: \"your-api-key\",\n  userId: savedUserId,\n});\n```\n\n### User ID Changed But Events Still Use Old ID\n\n**Issue:** After calling `identify()` with new user ID, some events still have old ID\n\n**Likely cause:** Events were queued before `identify()` was called\n\n**Solution:** This is expected behavior. Queued events retain their original user ID. Call `Axyle.flush()` after `identify()` to ensure new user ID is used for subsequent events.\n\n### TypeScript Errors\n\nEnsure peer dependencies are installed:\n\n```bash\nnpm install --save-dev @types/react @types/react-native\n```\n\n### Expo Go Issues\n\nThe SDK works in Expo Go without native modules. If you see issues:\n\n1. Clear cache: `npx expo start -c`\n2. Reinstall dependencies\n3. Device/app metadata will show default values — this is expected in Expo Go. Install `expo-application`, `expo-device`, and `expo-constants` with a dev build for full metadata.\n\n### SDK Not Initializing\n\nEnsure you're calling `init()` before any other SDK methods:\n\n```tsx\n// Correct order\nawait Axyle.init(\"api-key\");\nAxyle.track(\"Event\", {});\n\n// Wrong - track called before init\nAxyle.track(\"Event\", {});\nAxyle.init(\"api-key\");\n```\n\n## TypeScript\n\nThe SDK is fully typed. Import types as needed:\n\n```tsx\nimport type {\n  AnalyticsEvent,\n  EventProperties,\n  UserTraits,\n  SessionAnalyticsStats,\n} from \"@axyle/expo-sdk\";\n```\n\n## License\n\nMIT\n\n## Support\n\n- GitHub Issues: [Report a bug](https://github.com/axyle/expo-sdk/issues)\n- Documentation: [docs.axyle.com](https://docs.axyle.com)\n","readmeFilename":"README.md"}