@oursprivacy/react-native
v4.1.1
Published
Official React Native Tracking Library for OursPrivacy Analytics
Readme
Ours Privacy React Native SDK
Privacy-first analytics for React Native.
This SDK is pure JavaScript. It does not ship native iOS or Android modules. It supports Node 22+, React 18+, and React Native 0.76+. CI tests the React Native 0.76 floor and the current 0.87 demo.
Table of Contents
- Quick Start
- Upgrading to 4.0
- Mobile Instrumentation
- Complete Example
- API Reference
- Payload Structure
- FAQ
- Support
Upgrading to 4.0
Version 4.0 requires Node 22+, React 18+, and React Native 0.76+. Upgrade the app's React Native toolchain before installing this SDK version.
@react-native-async-storage/async-storage is now an optional peer. Install it directly in your app to keep visitor identity and queued events across restarts. Use Async Storage 2.2 with React Native 0.76 or Async Storage 3.1 with the React Native 0.87 demo. Without it, the SDK falls back to in-memory storage.
TypeScript event, custom, and consent property values must be JSON-compatible. Replace functions, class instances, and other unserializable values before calling track() or setting default properties. Optional undefined values remain valid and are omitted during JSON serialization. Consent can include boolean flags or string values.
Earlier React Native SDK versions emitted no lifecycle or screen events through trackAutomaticEvents. To adopt the $mobile_* contract, opt in with trackAutomaticEvents: true for lifecycle events and call trackScreen() from your navigator for screen views. Existing custom track() calls continue to work with automatic tracking off. Use canonical $mobile_* events for mobile engagement reporting. $deep_link_opened keeps its name, but no longer includes eventProperties.url; remove any downstream mapping that expects that property and use the allowlisted attribution fields in defaultProperties instead.
Quick Start
1. Install
npm install @oursprivacy/react-native
npm install @react-native-async-storage/async-storageInstall @react-native-async-storage/async-storage directly in your app if you want persistent storage in bare React Native projects. RN 0.76 apps should use Async Storage 2.2; the RN 0.87 demo uses Async Storage 3.1. The SDK accepts either major version as an optional peer.
Without it, the SDK falls back to in-memory storage.
2. Initialize
import { OursPrivacy } from '@oursprivacy/react-native';
const op = new OursPrivacy();
await op.init('YOUR_API_TOKEN');That's it. The SDK connects to https://cdn.oursprivacy.com by default — no endpoint configuration needed.
3. Track Events
op.track('Button Pressed');
op.track('Purchase', { value: 49.99, currency: 'USD' });4. Identify Users
After login, link events to a user:
await op.identify({
externalId: 'user-123',
email: '[email protected]',
firstName: 'Jane',
});5. Flush
Events are batched and sent every 10 seconds by default. To send immediately:
await op.flush();Mobile Instrumentation
On iOS and Android, every event (canonical, manual, and identify) carries defaultProperties.sid = String(Date.now()) captured at session start: a 13-digit decimal millisecond timestamp. Existing OS, device, and SDK version defaults remain. When capacity allows, SDK-owned eventProperties contain mobile_contract_version: 1, UTC ISO millisecond mobile_occurred_at, and app_version / app_build when supplied through appVersion / appBuild. The SDK owns mobile_contract_version and mobile_occurred_at; caller occurrence timestamps are replaced by the SDK call time. Explicit appVersion / appBuild options override caller values, while existing app_version / app_build event properties and registered defaults remain fallback values. The SDK emits neither mobile_session_started_at nor mobile_platform, and does not set top-level time.
Up to 196 ordinary event-property keys, including registered defaults, leave key capacity for all four metadata fields. Metadata also requires JSON.stringify(eventProperties).length < 1048576 (UTF-16 code units). If adding metadata would exceed either limit, the SDK omits these fields together and preserves all ordinary properties and session/device defaults. Larger bags may therefore be excluded from Mobile Analytics.
Existing visitor IDs or legacy install markers suppress first-open on upgrade; the SDK records the current host version/build when no earlier version was stored. Saved UUID sessions start a fresh session without repeating first-open. Queued legacy mobile events retain their captured occurrence, identity, and host version; missing occurrence times remain absent. Older events without mobile markers remain unchanged.
trackAutomaticEvents defaults to false. Set it to true to emit the automatic lifecycle events below. Manual track() and trackScreen() work with it off and still carry session metadata. The $mobile_* prefix is reserved for SDK-generated facts; track() ignores those names and logs a warning when logging is enabled. Existing $ae_* legacy names remain accepted. Full tracking opt-out suppresses both automatic and manual events, discards the current mobile session and unsent queued events, and clears registered default event, user custom, user consent, and attribution properties. It retains the current visitor ID; opt-in starts fresh mobile session state under that ID unless your app changes it. An opted-out launch does not consume the first-open marker.
For compatibility, successful HTTP responses with an empty body (including 204) or a JSON object without indexed fields acknowledge the full batch. Unknown response fields and an absent visitor_id are accepted. Indexed accepted counts and rejected index/code entries must cover the submitted batch with unique valid indexes. Nonempty malformed bodies, nonobject JSON, and invalid indexed acknowledgments retain the batch until the fifth malformed flush response for that queue head, then discard it with invalid_acknowledgment. Restarting the SDK resets the attempt count.
Explicit success: false rejects the batch with ingest_rejected, unless retryable: true is present. Permanent HTTP 4xx responses discard the batch with http_STATUS; 403, 408, 425, and 429 retain events for retry. The optional onIngestRejected listener receives only distinctId and code, after removal is saved. Failed saves, transport failures, server errors, and retryable rejections retain queued data. Queues have no size cap; unreadable saved queues recover as empty so future tracking can proceed. Each batch contains one captured visitor ID and identity mode; changing identity does not rewrite queued events. Older queue items without a captured mode use the current mode.
await op.init('YOUR_API_TOKEN', {
onIngestRejected: ({ distinctId, code }) => {
console.warn('Mobile event rejected', distinctId, code);
},
});| Canonical event | Trigger | Event properties |
| ---------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------ |
| $mobile_first_open | First eligible tracked foreground open for this installation and source token | None |
| $mobile_app_open | Each tracked foreground entry, including cold start | None |
| $mobile_session_start | First tracked foreground entry or the next entry after 30 minutes of inactivity | None |
| $mobile_session_engagement | Positive foreground-time delta at a checkpoint, tracked screen change, or background | engagement_duration_ms (integer); screen_name when known |
| $mobile_session_end | When a previously announced session is replaced | None |
| $mobile_app_update | First tracked open after a previously observed host version/build changes | previous_app_version, previous_app_build when known |
| $mobile_screen_view | An explicit trackScreen() call with a new active screen | screen_name |
$mobile_screen_view requires a route signal from your app; this JavaScript SDK does not observe React Navigation routes. Screen engagement belongs to the previously active screen when a new screen is tracked. Engagement duration is measured in integer milliseconds; a session becomes engaged after 10 accumulated foreground seconds. A session keeps its sid on a foreground return before 30 minutes of inactivity and rotates at 30 minutes. Background track() calls refresh inactivity, so apps with continuous background tracking may keep the session alive. A clock rollback greater than five minutes starts a new session. Session-end occurrence is the previous session's last activity, clamped to its start. A visitor ID change or reset ends an announced session; full opt-out silently discards it. The first tracked open remains first-open eligible until an eligible event is queued.
Backgrounding clears the active screen. Re-report the current screen on foreground resume when your navigation callback does not run. Re-initialization during the same foreground does not emit another app-open; with the same token, storage, and automatic-event setting, ongoing screen engagement continues. A source-token change can emit its first-open and session-start without another physical app-open. Rapid session rotations advance tied start timestamps by one millisecond, preserving distinct numeric IDs across restart and small clock rollback.
Canonical SDK telemetry contains lifecycle state, device/SDK metadata, and developer-supplied stable screen labels. Canonical $mobile_* facts carry no user properties or deep-link attribution. The SDK does not inspect screen content or collect advertising device IDs, patient fields, crash details, or network payloads automatically. Deep-link parsing extracts only allowlisted UTM parameters, click IDs, and ours_visitor_id; it does not add the full URL to a queued event or diagnostic. Keep PHI out of URLs, UTM values, screen labels, custom event names, and other caller-supplied properties. Click IDs may appear on $deep_link_opened and later manual events, but not on canonical $mobile_* facts.
Complete Example
import React from 'react';
import { Button, SafeAreaView } from 'react-native';
import { OursPrivacy } from '@oursprivacy/react-native';
let op;
async function getClient() {
if (!op) {
op = new OursPrivacy();
await op.init('YOUR_API_TOKEN', {
appVersion: '2.0.0',
appBuild: '42',
});
}
return op;
}
export default function App() {
return (
<SafeAreaView>
<Button
title="Track Event"
onPress={async () => {
const client = await getClient();
client.track('Button Pressed', { screen: 'Home' });
}}
/>
</SafeAreaView>
);
}API Reference
Initialization
new OursPrivacy()
Creates an OursPrivacy instance. The instance is unconfigured until you call .init(). All configuration (token, default properties, storage, etc.) is passed to init().
Returns: OursPrivacy instance.
const op = new OursPrivacy();op.init(token, options?)
Initialize the SDK. Must be called before any tracking method.
| Parameter | Type | Required | Description |
| --------- | ------------------------ | -------- | ---------------------------------- |
| token | string | Yes | Your project token |
| options | OursPrivacyInitOptions | No | Initialization options (see below) |
OursPrivacyInitOptions shape (all camelCase):
| Field | Type | Description |
| ------------------------------ | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| trackAutomaticEvents | boolean | Emit canonical mobile lifecycle events when true (default: false) |
| appVersion | string | Host app version, sent as eventProperties.app_version |
| appBuild | string | Host app build, sent as eventProperties.app_build |
| onIngestRejected | ({ distinctId, code }) => void | Optional listener for compatible indexed rejection responses |
| optOutTrackingByDefault | boolean | If true, start opted out only without a saved choice (default: false) |
| visitorId | string | Pre-set the visitor ID; sets is_manually_set_id: true on subsequent events |
| defaultEventProperties | object | Properties merged into eventProperties on every track() call |
| defaultUserCustomProperties | object | Properties merged into userProperties.custom_properties on every event |
| defaultUserConsentProperties | object | JSON-compatible values merged into userProperties.consent on every event |
| serverURL | string | Override the base URL used for requests, for example a local QA capture server |
| initialURL | string | Deep link URL to parse on init — extracts UTM params, click IDs, and ours_visitor_id (see Deep Link Attribution) |
| storage | OursPrivacyAsyncStorage | Custom AsyncStorage adapter |
Explicit opt-in and opt-out choices made by this SDK version take precedence over optOutTrackingByDefault after restart. A value written by this version's default follows later changes to that option. Unmarked legacy opt-ins use the configured default; legacy opt-outs remain opted out. A failed opt-in does not reopen tracking; opt-out fences tracking immediately even if its write fails. These failures reject the returned promise; retry the operation after storage recovers.
Returns: Promise<void>
// Minimal init
await op.init('YOUR_API_TOKEN');
// With options
await op.init('YOUR_API_TOKEN', {
visitorId: 'pre-known-id',
appVersion: '2.0.0',
appBuild: '42',
trackAutomaticEvents: true,
defaultEventProperties: { platform: 'mobile' },
defaultUserCustomProperties: { tier: 'pro' },
defaultUserConsentProperties: { marketing: true },
});Core Tracking
op.track(eventName, properties?)
Track an event with optional properties.
| Parameter | Type | Required | Description |
| ------------ | -------- | -------- | -------------------------------------- |
| eventName | string | Yes | Name of the event |
| properties | object | No | Key/value pairs to attach to the event |
Returns: Promise<void>
op.track('Page View', { page: '/home', referrer: 'google' });Screen Tracking
op.trackScreen(screenName)
Track a visible screen on iOS or Android. screenName must be a stable, developer-chosen label of 1–80 characters: start with an ASCII letter, then use only ASCII letters, numbers, spaces, underscores, or hyphens. Leading and trailing whitespace is rejected. Never pass a route path, URL, query string, route parameter, screen title containing patient data, or other dynamic identifier. A duplicate call for the current visible screen does not add another view. Call again when that screen is entered after a background/foreground transition.
Returns: Promise<void>
op.trackScreen('Schedule');For React Navigation, map fixed route names to approved labels. Initialize op before mounting the navigator. The onReady call captures the initial screen; onStateChange captures later transitions.
import {
createNavigationContainerRef,
NavigationContainer,
} from '@react-navigation/native';
const navigationRef = createNavigationContainerRef();
const screenLabels = new Map([
['HomeRoute', 'Home'],
['ScheduleRoute', 'Schedule'],
['ConfirmationRoute', 'Confirmation'],
]);
function trackCurrentScreen() {
const routeName = navigationRef.getCurrentRoute()?.name;
const screenName = routeName && screenLabels.get(routeName);
if (screenName) op.trackScreen(screenName);
}
<NavigationContainer
ref={navigationRef}
onReady={trackCurrentScreen}
onStateChange={trackCurrentScreen}
>
<RootNavigator />
</NavigationContainer>;Map route names only. Do not read route.params or derive labels from URLs. Automatic lifecycle tracking does not replace this explicit route integration, and trackScreen() remains available when trackAutomaticEvents is off.
op.identify(userProperties?)
Associate all future track() calls with the given user identity. Call this after a user logs in.
Pass identifying fields inside the userProperties bag — most commonly externalId (your system's user ID). Any default custom or consent properties registered via updateDefault* are merged in automatically.
| Parameter | Type | Required | Description |
| ---------------- | --------------------------- | -------- | ------------------------------------------ |
| userProperties | OursPrivacyUserProperties | No | User properties to attach to this identity |
OursPrivacyUserProperties shape (all camelCase):
| Field | Type | Description |
| ------------------ | -------- | ----------------------------------------------------------------------------------------- |
| email | string | User's email address |
| externalId | string | ID from your own system |
| phoneNumber | string | User's phone number |
| firstName | string | First name |
| lastName | string | Last name |
| gender | string | Gender |
| dateOfBirth | string | Date of birth (ISO 8601, e.g. 1990-04-12) |
| city | string | City |
| state | string | State / region |
| zip | string | Postal / ZIP code |
| country | string | Country (ISO 3166-1 alpha-2 preferred) |
| companyName | string | Company name |
| jobTitle | string | Job title |
| ip | string | Client IP (only set this if you have a reliable source — the server will infer otherwise) |
| customProperties | object | Arbitrary custom user attributes |
| consent | object | Consent values (e.g. { marketing: true } or { analytics: 'granted' }) |
The SDK converts these camelCase fields to the snake_case wire format (externalId → external_id, dateOfBirth → date_of_birth, etc.) before sending.
Returns: Promise<void>
await op.identify({
email: '[email protected]',
externalId: 'db-user-456',
firstName: 'Jane',
customProperties: { tier: 'pro' },
consent: { marketing: true },
});op.flush()
Attempt to send queued events immediately. Await the request before changing tracking consent. A failed request leaves events queued for retry.
Returns: Promise<void>
await op.flush();op.reset()
Clear the current user identity and all default properties. Generates a new random visitor ID. Call this when a user logs out.
Returns: Promise<void>
op.reset();Default Properties
Default properties are automatically merged into every event the SDK sends. They are the primary way to attach persistent, per-user or per-session context without repeating it on every track() call.
These methods can be called at init time via options, or at any point afterwards.
op.updateDefaultEventProperties(properties)
Merge properties into eventProperties on every future track() call. Properties are merged shallowly — later calls overwrite earlier ones for the same key.
| Parameter | Type | Required | Description |
| ------------ | -------- | -------- | ------------------------------------------------------ |
| properties | object | Yes | Key/value pairs to merge into default event properties |
Returns: void
// At init time:
await op.init('YOUR_API_TOKEN', {
defaultEventProperties: { app_version: '2.0.0', environment: 'production' },
});
// Or post-init (e.g. after fetching user data):
op.updateDefaultEventProperties({ experiment_group: 'variant_b' });
// Every subsequent track() will include these automatically:
op.track('Button Pressed'); // eventProperties includes app_version, environment, experiment_groupop.updateDefaultUserCustomProperties(properties)
Merge properties into userProperties.custom_properties on every future event. Useful for attaching user attributes that should travel with every event.
| Parameter | Type | Required | Description |
| ------------ | -------- | -------- | ------------------------------------------------------------ |
| properties | object | Yes | Key/value pairs to merge into default user custom properties |
Returns: void
// At init time:
await op.init('YOUR_API_TOKEN', {
defaultUserCustomProperties: { tier: 'pro' },
});
// Or post-init (e.g. after subscription status loads):
op.updateDefaultUserCustomProperties({ tier: 'enterprise', seats: 50 });op.updateDefaultUserConsentProperties(properties)
Merge properties into userProperties.consent on every future event. Use this to send the user's consent state alongside all analytics events.
| Parameter | Type | Required | Description |
| ------------ | -------- | -------- | ------------------------------------------------------------- |
| properties | object | Yes | Key/value pairs to merge into default user consent properties |
Returns: void
// At init time:
await op.init('YOUR_API_TOKEN', {
defaultUserConsentProperties: { marketing: false, analytics: true },
});
// Or when the user updates their preferences:
op.updateDefaultUserConsentProperties({ marketing: true });Configuration
op.setServerURL(serverURL)
Override the base URL after initialization.
| Parameter | Type | Required | Description |
| ----------- | -------- | -------- | ------------------------- |
| serverURL | string | Yes | Base URL for API requests |
Returns: void
op.setLoggingEnabled(loggingEnabled)
Enable or disable debug logging. All logging is disabled by default.
| Parameter | Type | Required | Description |
| ---------------- | --------- | -------- | ----------------------------- |
| loggingEnabled | boolean | Yes | Whether to enable SDK logging |
Returns: void
op.setLoggingEnabled(true);op.setFlushOnBackground(flushOnBackground)
Toggle automatic flushing when the app moves to the background. Enabled by default.
| Parameter | Type | Required | Description |
| ------------------- | --------- | -------- | ------------------------------------------------------------ |
| flushOnBackground | boolean | Yes | true to flush on background (default), false to disable. |
Returns: void
op.setFlushOnBackground(false);op.setFlushBatchSize(flushBatchSize)
Set the maximum number of events sent in a single network request. Maximum value is 50; values above 50 are clamped to 50.
| Parameter | Type | Required | Description |
| ---------------- | -------- | -------- | ----------------------------------- |
| flushBatchSize | number | Yes | Number of events per batch (max 50) |
Returns: void
op.setFlushBatchSize(25);Identity
op.getVisitorId()
Returns the stable visitor UUID for this install. Synchronous. No prefix.
Returns: string | null
const visitorId = op.getVisitorId();
console.log(visitorId); // e.g. "550e8400-e29b-41d4-a716-446655440000"op.setVisitorId(visitorId)
Update the visitor ID after initialization. Use this for web-to-app identity stitching when the visitor ID arrives outside of a deep link (e.g. via a native bridge or async lookup).
Sets is_manually_set_id: true on all subsequent events.
| Parameter | Type | Required | Description |
| ----------- | -------- | -------- | ------------------------------------ |
| visitorId | string | Yes | The Ours Privacy visitor ID to adopt |
Returns: Promise<void>
await op.setVisitorId('550e8400-e29b-41d4-a716-446655440000');Deep Link Attribution
op.trackDeepLink(url)
Parse a deep link URL for marketing attribution data and fire a $deep_link_opened event. Extracts UTM parameters, ad network click IDs, and ours_visitor_id for cross-platform identity stitching.
$deep_link_opened has no eventProperties.url; its eventProperties is null. The full URL is not included in SDK diagnostic logs. Parsed attribution params are merged into defaultProperties, so they appear on all subsequent track() calls. Calling trackDeepLink again replaces the prior attribution rather than merging, so stale UTM keys don't leak into events triggered by a later link. Keep PHI out of attribution values and use a stable, PHI-free label with trackScreen().
Await the returned promise before calling track() to ensure attribution and visitor identity are fully applied.
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ------------------------------------- |
| url | string | Yes | The deep link or initial URL to parse |
Returns: Promise<void>
import { Linking } from 'react-native';
// On cold start — await to ensure attribution is applied before tracking
const initialURL = await Linking.getInitialURL();
if (initialURL) {
await op.trackDeepLink(initialURL);
}
// On warm start (app in background)
Linking.addEventListener('url', async ({ url }) => {
await op.trackDeepLink(url);
});Alternatively, pass the URL at init time:
const initialURL = await Linking.getInitialURL();
await op.init('YOUR_API_TOKEN', {
initialURL: initialURL || undefined,
});Supported parameters:
| Category | Parameters |
| --------- | ------------------------------------------------------------------------ |
| UTM | utm_source, utm_medium, utm_campaign, utm_content, utm_term |
| Google | gclid, gad_source, dclid, gbraid, wbraid |
| Meta | fbclid, fbc, fbp |
| Microsoft | msclkid |
| TikTok | ttclid |
| Twitter/X | twclid |
| LinkedIn | li_fat_id |
| Reddit | rdt_cid |
| Snapchat | sccid |
| Pinterest | epik |
| Quora | qclid |
| AppLovin | aleid, alart, axwrt |
| Other | clickid, clid, ndclid, irclickid, im_ref, sacid, basis_cid |
| Identity | ours_visitor_id — cross-platform visitor stitching |
AppLovin example:
When a user clicks an AppLovin ad, the deep link will contain aleid (click ID) and alart (app user ID):
// Deep link: myapp://open?aleid=click_abc&alart=user_xyz&utm_source=applovin
await op.trackDeepLink(
'myapp://open?aleid=click_abc&alart=user_xyz&utm_source=applovin',
);
// All subsequent events will include aleid, alart, and utm_source in defaultPropertiesNote:
esi(Event Source Indicator) is configured in the AppLovin destination mapping in the Ours Privacy dashboard, not in the SDK. Set it to"app"for mobile events in your destination settings.
Privacy Controls
op.optOutTracking()
Stop all tracking immediately. Unsent queued events and the current mobile session are discarded, and registered default event, user custom, user consent, and attribution properties are cleared. The current visitor ID is retained, so events after opt-in use that ID with a fresh mobile session. Await flush() first to attempt delivery; a failed request remains queued and will be discarded by opt-out.
For an account switch, call reset() to generate a new visitor ID or setVisitorId() to adopt the intended ID, according to your app's policy, before tracking resumes. Keep PHI out of visitor IDs and manually supplied properties.
Returns: Promise<void>
await op.flush();
await op.optOutTracking();op.optInTracking()
Resume tracking after a previous call to optOutTracking(). This also sends an $opt_in event to the server.
Returns: Promise<void>
await op.optInTracking();op.hasOptedOutTracking()
Check whether the current user has opted out of tracking.
Returns: boolean. Before init() finishes loading consent, this returns true to prevent tracking. Await init() before reading the saved decision.
const hasOptedOut = op.hasOptedOutTracking();
if (hasOptedOut) {
console.log('User has opted out');
}Payload Structure
The SDK sends a JSON body to POST /ingest on the configured serverURL. Understanding this structure is useful if you are building a proxy, using the local QA capture server, or verifying your data in the Ours Privacy dashboard.
{
"token": "your-project-token",
"is_manually_set_id": false,
"data": [
{
"event": "Purchase",
"visitor_id": "550e8400-e29b-41d4-a716-446655440000",
"distinct_id": "ecff9f0e-d4f8-4d9e-b2f8-8d9b2fcdf7b2",
"eventProperties": {
"price": 99,
"mobile_contract_version": 1,
"mobile_occurred_at": "2026-10-05T12:00:02.000Z",
"app_version": "2.0.0",
"app_build": "42"
},
"userProperties": {
"custom_properties": {
"tier": "pro"
},
"consent": {
"marketing": true
}
},
"defaultProperties": {
"device_type": "mobile",
"os_name": "iOS",
"os_version": "17.0",
"device_vendor": "Apple",
"device_model": "iPhone 16 Pro",
"version": "[email protected]",
"sid": "1791201600000"
}
}
]
}Key fields:
| Field | Description |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| token | Your project token |
| is_manually_set_id | true when visitor ID was set via init() options, setVisitorId(), or ours_visitor_id in a deep link |
| data | Array of event objects in this batch |
| event | Event name |
| visitor_id | Stable visitor UUID for this install (no prefix) |
| distinct_id | Per-event UUID generated for this event occurrence |
| eventProperties | Caller event properties plus SDK-owned occurrence, contract, and host version metadata |
| userProperties.custom_properties | From identify() and updateDefaultUserCustomProperties() |
| userProperties.consent | From identify() and updateDefaultUserConsentProperties() |
| defaultProperties | Device/SDK metadata and the numeric session-start sid |
FAQ
Do I need to request permission through AppTrackingTransparency?
No. Ours Privacy does not use IDFA, so no ATT permission is required.
Why aren't my events showing up?
Events are batched and sent every 10 seconds by default. Await flush() to attempt to send them immediately. Enable debug logging with setLoggingEnabled(true) to see what's happening.
What platforms are supported?
- React Native >= 0.76
- iOS and Android apps using React Native
- Expo and other JavaScript-mode environments
