React Native
Official React Native SDK for Fluxner Analytics
The @fluxner/react-native SDK lets you track screens, events, errors, and users in React Native apps. Mobile sites get an App Analytics dashboard mode with mobile-specific labels (e.g. screen views instead of pageviews).
This documents the 0.2.0-next.0 preview download, not an npm registry release.
Physical React Native device validation is still pending. Existing 0.1.1
installations do not upgrade automatically. The current server acknowledges
queue admission, not durable storage; HTTP success is not a storage receipt.
This preview avoids automatic retries of uncertain events on that server.
Explicit safe retries need a compatible server response; the server
acknowledgement upgrade is not included in this rollout.
Creating a Mobile App Site
Before installing the SDK, create a site for your app in the Fluxner dashboard:
- Click Add Site and select the React Native app option instead of Website.
- Enter an app identifier (e.g.
com.example.app). Letters, numbers, dots, hyphens, and underscores are allowed. - Copy the Site ID — you'll pass it to
init().
Installation
npm install https://fluxner.com/source/fluxner-react-native-0.2.0-next.0.tgz @react-native-async-storage/async-storage@react-native-async-storage/async-storage is recommended but not strictly required. The SDK accepts any storage adapter with getItem/setItem/removeItem. Without one, it falls back to in-memory storage and the anonymous visitor ID will not persist across app launches, so every launch counts as a new visitor.
Initialization
fluxner.init() must be called once before any other tracking methods. Calling other methods first throws an error.
Syntax
async fluxner.init(config: FluxnerConfig): Promise<void>;Example
import AsyncStorage from "@react-native-async-storage/async-storage";
import fluxner from "@fluxner/react-native";
await fluxner.init({
analyticsHost: "https://fluxner.com/api",
siteId: "1",
appIdentifier: "com.example.app",
appVersion: "1.4.2",
storage: AsyncStorage,
initialScreenName: "Home",
});Configuration Options
Required Options
| Option | Type | Description |
|---|---|---|
analyticsHost | string | URL of your Fluxner instance's API (e.g., https://fluxner.yourdomain.com/api). |
siteId | string | number | The Site ID for your app obtained from your Fluxner instance. |
Optional Options
| Option | Type | Default | Description |
|---|---|---|---|
appIdentifier | string | "" | Identifier for your app (e.g., com.example.app). Used as the hostname in tracked data. Falls back to bundleId, then the site ID. |
bundleId | string | "" | Alias for appIdentifier; used when appIdentifier is not set. |
appVersion | string | "" | Your app's version. Appended to the synthetic user agent sent with each event. |
tag | string | "" | A tag added to every event, useful for segmenting data (e.g., by environment or build channel). |
storage | FluxnerStorage | in-memory | Storage adapter used to persist the anonymous visitor ID and identified user ID. Pass AsyncStorage or any compatible object. |
storageKeyPrefix | string | "@fluxner" | Prefix for storage keys. Keys are namespaced per site: {prefix}:{siteId}:anonymous-id. |
debug | boolean | false | Log SDK warnings (failed requests, config fetch failures) to the console. |
autoTrackAppLifecycle | boolean | true | Automatically track app_open and app_background events on AppState changes. See App Lifecycle Events. |
initialScreenName | string | "" | If set, a screen view for this name is tracked during init() (unless Track Initial Pageview is disabled in your dashboard). |
configTimeoutMs | number | 3000 | Timeout in milliseconds for fetching remote tracking config during init(). On timeout or failure, the SDK proceeds with defaults. |
maxQueueSize | number | 100 | Positive integer limit for all pending events, including in-flight requests. A separate 1 MiB serialized-body budget also applies. See Offline Handling. |
fetch | typeof fetch | global | Custom fetch implementation. Defaults to the global fetch. |
Remote Configuration
During init(), the SDK fetches your site's tracking settings from the dashboard. Two of them affect the React Native SDK:
| Dashboard Setting | Effect |
|---|---|
| Track Initial Pageview | When disabled, the initialScreenName screen view is not tracked on init. |
| Capture Errors | When disabled, calls to fluxner.error() are silently ignored. |
Web-only settings (session replay, Web Vitals, outbound links, autocapture) do not apply to mobile apps.
Tracking Screens
Screens are the mobile equivalent of pageviews. Each screen view is tracked with the screen name as both the path and title.
Syntax
fluxner.screen(name: string, properties?: TrackProperties, context?: TrackContext): Promise<DeliveryResult>;Parameters
name(string, Required): The screen name (e.g.,"Home","Checkout"). Used as the pathname (/Home) and page title.properties(object, Optional): Additional key-value pairs attached to the screen view.context(object, Optional): Overrides for the tracked payload. See Track Context.
Example
await fluxner.screen("Checkout");
// With properties and an explicit path
await fluxner.screen("Product", { productId: "sku-123" }, { pathname: "/products/sku-123" });You can also track a raw path directly, mirroring the web SDK:
fluxner.pageview(path?: string, context?: TrackContext): Promise<DeliveryResult>;React Navigation
The SDK ships a navigation tracker that hooks into React Navigation's NavigationContainer and automatically tracks a screen view whenever the active route changes. Consecutive events for the same route name are deduplicated.
import { NavigationContainer, useNavigationContainerRef } from "@react-navigation/native";
import fluxner from "@fluxner/react-native";
const navigationTracker = fluxner.createNavigationTracker();
function App() {
const navigationRef = useNavigationContainerRef();
return (
<NavigationContainer
ref={navigationRef}
onReady={() => navigationTracker.onReady(navigationRef)}
onStateChange={() => navigationTracker.onStateChange(navigationRef)}
>
{/* screens */}
</NavigationContainer>
);
}Options
fluxner.createNavigationTracker(options?: NavigationTrackerOptions): NavigationTracker;| Option | Type | Default | Description |
|---|---|---|---|
includeRouteParams | boolean | false | Include the route's params as a routeParams property on the screen view. |
getRouteName | (route) => string | route.name | Customize how the screen name is derived from the current route. |
getPath | (route) => string | route.path or route.name | Customize the tracked pathname for the current route. |
The returned tracker exposes onReady, onStateChange, and trackCurrentRoute — all take the navigation ref and track the current route if it changed. It works with any navigation library whose ref exposes a getCurrentRoute() method.
Route params can contain sensitive data (IDs, tokens, emails). Only enable includeRouteParams if your route params are safe to store in analytics.
Tracking Custom Events
Syntax
fluxner.event(name: string, properties?: TrackProperties, context?: TrackContext): Promise<DeliveryResult>;Parameters
name(string, Required): The name of the event you want to track.properties(object, Optional): Additional key-value pairs related to the event.
Example
await fluxner.event("signup_started", { plan: "pro" });
await fluxner.event("purchase_completed", {
orderId: "order-123",
total: 49.99,
currency: "USD",
});Error Tracking
Capture handled errors with additional context. Error tracking must be enabled in your Fluxner dashboard (Capture Errors) — when disabled, error() calls are ignored.
Syntax
fluxner.error(error: Error | unknown, properties?: TrackProperties, context?: TrackContext): Promise<DeliveryResult>;Non-Error values are converted to an Error. The message is truncated to 500 characters and the stack trace to 2,000.
Example
try {
await processPayment(order);
} catch (error) {
await fluxner.error(error, { component: "checkout", orderId: order.id });
showErrorMessage();
}Unlike the web SDK, the React Native SDK does not automatically capture uncaught exceptions — wrap the code you care about and call fluxner.error() yourself.
User Identification
Associate events with a user ID and optional traits. The ID is persisted through the configured storage adapter and attached to all subsequent events.
fluxner.identify(userId: string, traits?: Record<string, unknown>): Promise<void>;
fluxner.setTraits(traits: Record<string, unknown>): Promise<void>;
fluxner.clearUserId(): Promise<void>;
fluxner.getUserId(): string | null;// After login
await fluxner.identify("user_123", { plan: "pro", signupDate: "2026-01-15" });
// Update traits later without changing the ID
await fluxner.setTraits({ plan: "enterprise" });
// After logout
await fluxner.clearUserId();setTraits() throws if no user has been identified yet — call identify() first.
App Lifecycle Events
With autoTrackAppLifecycle enabled (the default), the SDK listens to React Native's AppState and tracks:
app_open— when the app launches in the foreground or returns to the foreground from the background.app_background— when the app leaves the foreground, with astateproperty ("background"or"inactive").
Set autoTrackAppLifecycle: false in init() to disable these events.
Offline Handling and Retries
Tracking returns a DeliveryResult: accepted, retryable, unconfirmed,
not_sent (queue capacity), or disabled (error tracking disabled).
accepted means HTTP success, including intentional server exclusions and
limits; it does not always mean an event was stored.
Only an HTTP 503 response containing success: false,
code: "FLUXNER_EVENT_NOT_SUBMITTED", and retryable: true permits retry.
Network failures, 35-second timeouts, malformed/legacy responses and other
HTTP failures remain unconfirmed. They stay inspectable but are not resent.
Pending entries include in-flight requests and share maxQueueSize (default
100) plus a fixed 1 MiB UTF-16 serialized-body budget, not a total heap limit.
When full, the new event returns not_sent without sending or retaining it;
old entries are never silently evicted. Retryable entries get one attempt per
flush, and overlapping flush calls share one pass:
fluxner.flush(): Promise<void>;
fluxner.getPendingEvents(): PendingEvent[];
fluxner.discardPending(id: string): boolean;Pending payloads may contain private data; do not send snapshots to public logs.
Discard is explicit abandonment, not cancellation of a server write, and is
refused while an entry is in-flight or its transportPending flag is true,
including after timeout. A hung transport retains its capacity reservation.
Do not manually resend an uncertain event. Navigation helpers return the delivery
result (or undefined for an unchanged/missing route), allowing a capacity-rejected
route to be attempted again without automatically resending an uncertain event.
Reinitialization is refused while events or initialization are pending.
The queue is in-memory only. AsyncStorage persists identity, not pending events; app/process restart loses them. This prevents the uncertain automatic retry path, not every duplicate or loss. Old SDKs retain the previous behavior. The server proof covers main-event submission, not session/detection counters, and is withheld when a bot observation may have been written.
Track Context
All tracking methods accept an optional context object to override what's sent with that event:
| Field | Type | Description |
|---|---|---|
appIdentifier | string | Override the hostname for this event. |
pathname | string | Override the tracked path. |
querystring | string | Query string to attach to the event. |
screen | string | Screen name, used as the path/title fallback. |
title | string | Override the page title. |
referrer | string | Referrer value (empty by default on mobile). |
language | string | Override the detected device locale. |
userAgent | string | Override the synthetic user agent. |
Device locale, screen dimensions, and a platform-appropriate user agent (including your appVersion) are detected automatically.
Cleanup
Removes the AppState lifecycle listener. Call it if you tear down the SDK, e.g. in tests or when unmounting your app root.
fluxner.cleanup(): void;Differences from the Web SDK
- Session replay and Web Vitals are web-only and not available for React Native apps.
- No automatic outbound link, button click, form, or copy tracking (there is no DOM).
- Uncaught errors are not captured automatically — use
fluxner.error()in your own error boundaries and catch blocks. - The anonymous visitor ID is generated by the SDK and persisted via your storage adapter, rather than derived from browser fingerprinting.