npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@grafana/faro-react-native-tracing

v1.3.0

Published

Faro React Native tracing implementation with OpenTelemetry.

Readme

@grafana/faro-react-native-tracing

OpenTelemetry distributed tracing integration for Faro React Native SDK.

Installation

npm install @grafana/faro-react-native-tracing
# or
yarn add @grafana/faro-react-native-tracing

Prerequisites:

  • @grafana/faro-react-native - Core Faro SDK for React Native
  • React Native 0.70 or higher

Quick Start

Enable tracing via the enableTracing flag—no need to add TracingInstrumentation to instrumentations:

import { initializeFaro } from '@grafana/faro-react-native';

const faro = initializeFaro({
  url: 'https://faro-collector-prod-YOUR-REGION.grafana.net/collect/YOUR_TOKEN_HERE',
  app: {
    name: 'my-react-native-app',
    version: '1.0.0',
    environment: 'production',
  },
  enableTracing: true,
  tracingOptions: {
    // Optional: Propagate trace headers to these URLs for distributed tracing
    instrumentationOptions: {
      propagateTraceHeaderCorsUrls: [/https:\/\/my-api\.com/],
    },
  },
});

That's it! HTTP requests via fetch() are now automatically traced (and correlated with user actions when user action tracking is enabled) and sent to your Faro collector.

Fetch vs XHR in React Native

By default, this package traces fetch() requests only.

React Native implements fetch() on top of XMLHttpRequest. If both fetch and XHR instrumentation are enabled for the same URL, one logical fetch() request can produce two spans: one from FetchInstrumentation and one from the underlying XHR layer. To avoid duplicate HTTP telemetry, XHR tracing is disabled by default.

If your app uses axios or direct XMLHttpRequest calls instead of fetch(), enable XHR tracing explicitly:

initializeFaro({
  enableTracing: true,
  tracingOptions: {
    instrumentationOptions: {
      enableXhrInstrumentation: true,
    },
  },
});

If your app uses both fetch() and axios/XHR, avoid tracing the same request twice. Either trace one API surface only:

initializeFaro({
  enableTracing: true,
  tracingOptions: {
    instrumentationOptions: {
      // Useful for axios/direct XHR apps.
      enableFetchInstrumentation: false,
      enableXhrInstrumentation: true,
    },
  },
});

Or enable both and use ignoreUrls on one instrumentation so URL patterns do not overlap:

initializeFaro({
  enableTracing: true,
  tracingOptions: {
    instrumentationOptions: {
      enableXhrInstrumentation: true,
      xhrInstrumentationOptions: {
        // Example: fetch() handles your API calls, so ignore those URLs in XHR.
        ignoreUrls: [/\/api\//],
      },
    },
  },
});

Features

🚀 Automatic Tracing

  • Fetch Instrumentation: fetch() requests are automatically traced with no code changes
  • Optional XHR Instrumentation: Enable for axios or direct XMLHttpRequest calls
  • Session Correlation: Traces are correlated with Faro sessions for complete user journey tracking
  • User Action Correlation: Traces are correlated with Faro user actions (when user action tracking is enabled)
  • User Context: User information is automatically added to span attributes
  • Device Metadata: Device and platform information included in traces (device model, OS, locale, etc.)

🔗 Distributed Tracing

  • W3C Trace Context: Standards-compliant trace propagation via HTTP headers
  • Context Propagation: Seamlessly connect frontend traces to backend services
  • Configurable CORS: Control which APIs receive trace headers

🎯 Manual Span Creation

  • OTEL API Access: Full OpenTelemetry API available via faro.otel
  • Custom Spans: Create spans for critical business operations
  • Nested Spans: Build complex trace hierarchies with parent-child relationships
  • Span Attributes: Add custom metadata to spans for rich context
  • Span Events: Add timestamped checkpoints within spans

🔍 Faro Integration

  • User Action Correlation: Spans are correlated with Faro user actions
  • Log Correlation: Connect traces with logs using trace/span IDs
  • Error Correlation: Errors are automatically linked to active spans
  • Measurement Correlation: Performance metrics tied to traces

🛡️ Infinite Loop Prevention

The tracing instrumentation is carefully designed to prevent infinite loops that can occur when tracing causes logging, which causes more tracing:

  • Automatic URL Filtering: Collector URLs are automatically excluded from tracing
  • Trailing Slash Handling: Handles URL variations (with/without trailing slashes)
  • Internal Logging: Uses internalLogger instead of console.log internally
  • Batch Processing: BatchSpanProcessor delays span export to avoid blocking
  • No Logging During Export: Zero console output during trace export

Configuration Options

When using enableTracing: true, pass options via tracingOptions in your Faro config. For manual setup (e.g. custom config without makeRNConfig), add TracingInstrumentation to instrumentations:

Basic Configuration

// Via flag (recommended):
initializeFaro({
  enableTracing: true,
  tracingOptions: {
    resourceAttributes: { 'deployment.environment': 'staging' },
    instrumentationOptions: {
      propagateTraceHeaderCorsUrls: [/https:\/\/api\.example\.com/],
    },
  },
});

// Or manually:
new TracingInstrumentation({
  // Optional: Add custom resource attributes
  resourceAttributes: {
    'service.namespace': 'mobile-apps',
    'deployment.environment': 'staging',
    'custom.attribute': 'value',
  },

  // Optional: Configure trace header propagation
  instrumentationOptions: {
    // URLs that should receive trace context headers
    propagateTraceHeaderCorsUrls: [/https:\/\/api\.example\.com/, 'https://other-api.com'],

    // Optional: enable XHR tracing for apps that use axios or XHR directly.
    // Disabled by default because React Native's current fetch implementation is backed by XHR.
    enableXhrInstrumentation: false,

    // Optional: Customize fetch instrumentation
    fetchInstrumentationOptions: {
      // Ignore network performance events (default: true)
      ignoreNetworkEvents: true,

      // Optional: Add custom attributes to spans
      applyCustomAttributesOnSpan: (span, request, response) => {
        span.setAttribute('http.custom', 'value');
        span.setAttribute('http.request_id', request.headers['x-request-id']);
      },
    },
  },
});

Advanced Configuration

import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { FaroTraceExporter, FaroMetaAttributesSpanProcessor } from '@grafana/faro-react-native-tracing';

new TracingInstrumentation({
  // Optional: Custom span processor (advanced)
  spanProcessor: new FaroMetaAttributesSpanProcessor(
    new BatchSpanProcessor(new FaroTraceExporter({ api: faro.api }), {
      scheduledDelayMillis: 1000,
      maxExportBatchSize: 30,
      maxQueueSize: 100,
    }),
    faro.metas
  ),

  // Optional: Custom OTEL instrumentations (advanced)
  instrumentations: [
    // Your custom OpenTelemetry instrumentations
  ],
});

Usage Examples

Automatic HTTP Tracing

fetch() requests are automatically traced with no code changes:

// This fetch call is automatically traced by default.
const response = await fetch('https://api.example.com/users');
const data = await response.json();

// The span includes:
// - HTTP method, URL, status code
// - Request/response headers (if configured)
// - Duration
// - Session ID, user info
// - Device metadata

Axios and Direct XHR Tracing

Axios and direct XMLHttpRequest calls require XHR instrumentation:

initializeFaro({
  enableTracing: true,
  tracingOptions: {
    instrumentationOptions: {
      enableXhrInstrumentation: true,
    },
  },
});

If the same app also uses fetch() for the same backend URLs, add ignoreUrls to either fetch or XHR instrumentation to avoid duplicate spans.

Trace includes:

  • http.method: GET
  • http.url: https://api.example.com/users
  • http.status_code: 200
  • session.id: abc123
  • device.model: iPhone 15 Pro
  • device.platform: iOS
  • Plus all Faro metas (user, device, session, etc.)

Manual Span Creation

Create custom spans for business operations:

import { faro } from '@grafana/faro-react-native';

async function processOrder(orderId: string) {
  // Access OpenTelemetry API via faro.otel
  const { trace } = faro.otel;
  const tracer = trace.getTracer('my-app');

  // Create a span
  const span = tracer.startSpan('process-order', {
    attributes: {
      'order.id': orderId,
      'operation.type': 'payment',
    },
  });

  try {
    // Your business logic here
    const payment = await processPayment(orderId);

    // Add attributes as you go
    span.setAttribute('payment.amount', payment.amount);
    span.setAttribute('payment.currency', payment.currency);

    // Add an event (checkpoint)
    span.addEvent('payment_validated', {
      'validator.id': payment.validatorId,
    });

    // Mark span as successful
    span.setStatus({ code: SpanStatusCode.OK });
  } catch (error) {
    // Mark span as error
    span.setStatus({
      code: SpanStatusCode.ERROR,
      message: error.message,
    });
    span.recordException(error);
    throw error;
  } finally {
    // Always end the span
    span.end();
  }
}

Nested Spans (Parent-Child Relationships)

Build complex trace hierarchies:

import { faro } from '@grafana/faro-react-native';
import { SpanStatusCode } from '@opentelemetry/api';

async function checkoutFlow(cartId: string) {
  const { trace, context } = faro.otel;
  const tracer = trace.getTracer('my-app');

  // Create parent span
  const parentSpan = tracer.startSpan('checkout-flow', {
    attributes: { 'cart.id': cartId },
  });

  try {
    // Use context.with() to make this span the active parent
    await context.with(trace.setSpan(context.active(), parentSpan), async () => {
      // Child span 1: Validate cart
      const validateSpan = tracer.startSpan('validate-cart');
      await validateCart(cartId);
      validateSpan.setStatus({ code: SpanStatusCode.OK });
      validateSpan.end();

      // Child span 2: Process payment
      const paymentSpan = tracer.startSpan('process-payment');
      await processPayment(cartId);
      paymentSpan.setStatus({ code: SpanStatusCode.OK });
      paymentSpan.end();

      // Child span 3: Send confirmation
      const confirmSpan = tracer.startSpan('send-confirmation');
      await sendConfirmation(cartId);
      confirmSpan.setStatus({ code: SpanStatusCode.OK });
      confirmSpan.end();
    });

    parentSpan.setStatus({ code: SpanStatusCode.OK });
  } catch (error) {
    parentSpan.setStatus({
      code: SpanStatusCode.ERROR,
      message: error.message,
    });
    parentSpan.recordException(error);
  } finally {
    parentSpan.end();
  }
}

Correlation with Faro User Actions

Spans are automatically correlated with user actions:

import { faro } from '@grafana/faro-react-native';
import { withFaroUserAction } from '@grafana/faro-react-native';
import { TouchableOpacity } from 'react-native';

// Create a tracked button
const TrackedButton = withFaroUserAction(TouchableOpacity, 'load-data');

function DataLoader() {
  const handleLoad = async () => {
    // This fetch will be traced AND correlated with the user action
    // The span will include: faro.action.user.name = "load-data"
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
  };

  return (
    <TrackedButton onPress={handleLoad}>
      <Text>Load Data</Text>
    </TrackedButton>
  );
}

Correlation with Faro Logs

Connect traces with logs for full observability:

import { faro } from '@grafana/faro-react-native';
import { SpanStatusCode } from '@opentelemetry/api';

function performOperation() {
  const { trace, context } = faro.otel;
  const tracer = trace.getTracer('my-app');
  const span = tracer.startSpan('important-operation');

  // Run operation within span context
  context.with(trace.setSpan(context.active(), span), () => {
    // This log will be correlated with the span
    // via trace_id and span_id in the log meta
    faro.api.pushLog(['Operation started'], {
      context: 'operations',
      level: 'info',
    });

    // Do work...

    faro.api.pushLog(['Operation completed successfully'], {
      context: 'operations',
      level: 'info',
    });

    span.setStatus({ code: SpanStatusCode.OK });
    span.end();
  });
}

How It Works

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Your React Native App                     │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       │ fetch() / XHR calls
                       ↓
┌─────────────────────────────────────────────────────────────┐
│       FetchInstrumentation, optionally XMLHttpRequest        │
│  • Intercepts fetch() by default                            │
│  • Creates spans automatically                               │
│  • Propagates W3C Trace Context headers                      │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       │ Spans
                       ↓
┌─────────────────────────────────────────────────────────────┐
│     HttpRequestMonitorSpanProcessor (user action correlation) │
│  • Notifies httpRequestMonitor for user action halt logic    │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       │ Spans
                       ↓
┌─────────────────────────────────────────────────────────────┐
│           FaroMetaAttributesSpanProcessor                    │
│  • Adds Faro metas (session, user) to spans                  │
│  • Device/service from resource                              │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       │ Enriched spans
                       ↓
┌─────────────────────────────────────────────────────────────┐
│              BatchSpanProcessor (OTEL)                       │
│  • Batches spans (max 30, delay 1000ms)                     │
│  • Reduces network requests                                  │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       │ Span batches
                       ↓
┌─────────────────────────────────────────────────────────────┐
│                 FaroTraceExporter                            │
│  • Converts spans to OTLP format                             │
│  • Sends to Faro collector via pushTraces()                  │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       │ OTLP/HTTP
                       ↓
┌─────────────────────────────────────────────────────────────┐
│              Grafana Cloud / Faro Collector                  │
│  • Receives traces                                           │
│  • Stores in Tempo                                           │
│  • Links traces ↔ logs ↔ metrics                             │
└─────────────────────────────────────────────────────────────┘

Span Lifecycle

  1. Span Creation: FetchInstrumentation creates a span when fetch() is called; XMLHttpRequestInstrumentation can be enabled for XHR/axios apps. W3C Trace Context headers are added to the request if the URL matches propagateTraceHeaderCorsUrls.
  2. Enrichment: HttpRequestMonitorSpanProcessor notifies for user action correlation; FaroMetaAttributesSpanProcessor adds session and user to spans (device/service come from resource)
  3. Batching: BatchSpanProcessor collects spans (max 30 spans or 1000ms delay)
  4. Export: FaroTraceExporter converts spans to OTLP format; also sends Faro events (e.g. faro.tracing.fetch) for CLIENT spans
  5. Transmission: Spans sent to Faro collector via faro.api.pushTraces()

Span Attributes

Every span includes these attributes:

Standard OTEL Attributes:

  • http.method - HTTP method (GET, POST, etc.)
  • http.url - Full URL
  • http.status_code - HTTP status code
  • http.target - URL path

Faro Session Attributes:

  • session.id - Faro session ID

User Attributes (if set):

  • user.id - User ID
  • user.name - Username
  • user.email - Email

Device Attributes (from resource):

  • device.model - Device model (e.g., "iPhone 15 Pro")
  • device.brand - Device manufacturer (e.g., "Apple")
  • device.platform - OS name (e.g., "iOS")
  • device.os.version - OS version (e.g., "17.0")
  • device.locale - Device locale (e.g., "en-US")

App Attributes (from resource):

  • service.name - App name from config
  • service.version - App version
  • service.namespace - App namespace (if set)
  • deployment.environment.name - Environment (production, staging, etc.)

User Action Attributes (if active):

  • faro.action.user.name - Name of user action
  • faro.action.user.parentId - Parent action ID

Distributed Tracing

Connecting Frontend to Backend

To enable full distributed tracing, configure your backend to accept W3C Trace Context headers:

// Frontend (React Native)
new TracingInstrumentation({
  instrumentationOptions: {
    // Propagate headers to your API
    propagateTraceHeaderCorsUrls: [/https:\/\/api\.example\.com/],
  },
});

// Backend (Node.js + Express + OpenTelemetry)
const { W3CTraceContextPropagator } = require('@opentelemetry/core');
const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');

const provider = new NodeTracerProvider();
provider.register({
  propagator: new W3CTraceContextPropagator(),
});

When configured correctly:

  1. Frontend creates a span for the HTTP request
  2. Frontend adds traceparent and tracestate headers to the request
  3. Backend extracts trace context from headers
  4. Backend creates child spans linked to frontend trace
  5. Both frontend and backend spans appear in the same trace in Grafana

Example Distributed Trace

Trace: abc123-def456-ghi789

├─ [Frontend] fetch POST /api/orders (250ms)
│  ├─ [Backend] POST /api/orders (200ms)
│  │  ├─ [Backend] validate-order (10ms)
│  │  ├─ [Backend] query-database (150ms)
│  │  └─ [Backend] send-email (40ms)
│  └─ [Frontend] parse-response (5ms)

Troubleshooting

No traces appearing in Grafana Cloud

Check session sampling:

const session = faro.api.getSession();
console.log('Session:', session);
console.log('Is sampled:', session?.attributes?.isSampled);

If isSampled is false, traces won't be collected. Adjust session sampling in the core SDK config (omit sampling for 100%):

import { initializeFaro, SamplingRate } from '@grafana/faro-react-native';

initializeFaro({
  // ...
  sessionTracking: {
    sampling: new SamplingRate(1), // 100% of sessions
  },
});

Verify collector URL:

// Check that URL is correctly formatted
console.log('Collector URL:', faro.config.url);

Check network requests: Open React Native debugger → Network tab → Look for POST requests to /collect/

Infinite loops / exponential requests

Symptoms:

  • App sends exponentially growing requests
  • App becomes unresponsive
  • Dev tools crash

Cause: Trace export requests are being traced, creating an infinite loop.

Solution: This should be automatically prevented. If you experience this issue:

  1. Update to latest version - Infinite loop prevention was fixed in recent versions
  2. Check for custom span processors - Don't use console.log in custom processors
  3. Verify URL filtering - Collector URLs should be automatically excluded
// Debug: Check which URLs are being ignored
const ignoredUrls = transport.getIgnoreUrls();
console.log('Ignored URLs:', ignoredUrls);

OTEL is not available error

Error:

OTEL is not available. Make sure tracing is initialised

Cause: Trying to use faro.otel before TracingInstrumentation is initialized.

Solution:

// ✅ Correct: Initialize tracing first
const faro = initializeFaro({
  instrumentations: [new TracingInstrumentation()],
});

// Then use faro.otel
const { trace } = faro.otel;

// ❌ Wrong: Using faro.otel without tracing instrumentation
const faro = initializeFaro({
  instrumentations: [], // No tracing!
});
const { trace } = faro.otel; // Error!

Trace IDs are all zeros (00000000000000000000000000000000)

Cause: TracerProvider is not registered as the global provider.

Solution: This should be automatic. If you're using a custom span processor or custom instrumentations, ensure you're not overriding the tracer provider registration.

Spans missing user/session/device context

Cause: FaroMetaAttributesSpanProcessor is not wrapping your span processor.

Solution: Use the default span processor or ensure you wrap your custom processor:

import { FaroMetaAttributesSpanProcessor } from '@grafana/faro-react-native-tracing';

new TracingInstrumentation({
  spanProcessor: new FaroMetaAttributesSpanProcessor(yourCustomSpanProcessor, faro.metas),
});

Backend spans not appearing in frontend trace

Cause: Backend is not configured to accept W3C Trace Context headers, or CORS is blocking headers.

Solutions:

  1. Enable W3C propagator on backend:
// Node.js + OpenTelemetry
const { W3CTraceContextPropagator } = require('@opentelemetry/core');
provider.register({
  propagator: new W3CTraceContextPropagator(),
});
  1. Configure CORS to allow trace headers:
// Express
app.use(
  cors({
    allowedHeaders: ['traceparent', 'tracestate'],
  })
);
  1. Add backend URL to propagation list:
new TracingInstrumentation({
  instrumentationOptions: {
    propagateTraceHeaderCorsUrls: [/https:\/\/your-backend\.com/],
  },
});

API Reference

TracingInstrumentation

Main instrumentation class for distributed tracing.

class TracingInstrumentation extends BaseInstrumentation {
  constructor(options?: TracingInstrumentationOptions);
  initialize(): void;
  shutdown(): Promise<void>;
}

Options:

interface TracingInstrumentationOptions {
  // Custom OTEL resource attributes
  resourceAttributes?: Attributes;

  // Custom OTEL propagator (default: W3CTraceContextPropagator)
  propagator?: TextMapPropagator;

  // Custom OTEL context manager (default: StackContextManager)
  contextManager?: ContextManager;

  // Custom OTEL instrumentations (replaces default fetch/XHR instrumentations)
  instrumentations?: Instrumentation[];

  // Custom span processor (replaces default BatchSpanProcessor)
  spanProcessor?: SpanProcessor;

  // Instrumentation options
  instrumentationOptions?: {
    // URLs to propagate trace headers to
    propagateTraceHeaderCorsUrls?: Array<string | RegExp>;

    // Enable fetch instrumentation (default: true)
    enableFetchInstrumentation?: boolean;

    // Enable XHR instrumentation (default: false)
    enableXhrInstrumentation?: boolean;

    // Fetch instrumentation options
    fetchInstrumentationOptions?: {
      // Custom attributes function
      applyCustomAttributesOnSpan?: FetchCustomAttributeFunction;

      // Ignore network events (default: true)
      ignoreNetworkEvents?: boolean;
    };
  };
}

FaroTraceExporter

Exports OpenTelemetry spans to Faro collector.

class FaroTraceExporter implements SpanExporter {
  constructor(config: FaroTraceExporterConfig);
  export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void;
  shutdown(): Promise<void>;
}

getDefaultOTELInstrumentations()

Returns default OpenTelemetry instrumentations for React Native.

function getDefaultOTELInstrumentations(options?: DefaultInstrumentationsOptions): Instrumentation[];

Currently returns:

  • FetchInstrumentation - Automatic HTTP tracing
  • XMLHttpRequestInstrumentation - Optional; enabled with enableXhrInstrumentation: true

faro.otel

Access OpenTelemetry APIs for manual tracing.

interface FaroOTEL {
  trace: TraceAPI; // OpenTelemetry trace API
  context: ContextAPI; // OpenTelemetry context API
}

// Usage
const { trace, context } = faro.otel;
const tracer = trace.getTracer('my-app');
const span = tracer.startSpan('operation');

Best Practices

✅ DO

  • Use automatic tracing - Let FetchInstrumentation handle HTTP requests
  • Add meaningful attributes - Include business context in spans
  • Use span events - Add checkpoints for important operations
  • Set span status - Mark spans as OK or ERROR
  • End spans - Always call span.end() in a finally block
  • Use context.with() - For nested spans
  • Correlate with user actions - Use withFaroUserAction HOC
  • Configure propagation - Add your APIs to propagateTraceHeaderCorsUrls
  • Sample sessions - Use sampling for high-traffic apps

❌ DON'T

  • Don't use console.log in span processors - Causes infinite loops
  • Don't forget to end spans - Causes memory leaks
  • Don't create spans for trivial operations - Keep trace volume reasonable
  • Don't include PII in span attributes - Respect user privacy
  • Don't trace internal URLs - Collector URLs are auto-excluded
  • Don't create deeply nested spans - Keep hierarchy shallow (< 10 levels)

Examples

See the demo app for complete examples:

Performance Considerations

Overhead

  • Automatic tracing: ~5-10ms per HTTP request
  • Manual spans: ~0.5-1ms per span
  • Batch processing: Minimal impact (1000ms delay)

Optimization Tips

  1. Sample sessions - Don't trace every session:
import { SamplingRate } from '@grafana/faro-react-native';

// ...
sessionTracking: {
  sampling: new SamplingRate(0.1), // 10% of sessions
}
  1. Increase batch size - Reduce network requests:
new BatchSpanProcessor(exporter, {
  maxExportBatchSize: 50, // Default: 30
  scheduledDelayMillis: 2000, // Default: 1000
});
  1. Filter spans - Don't trace everything:
fetchInstrumentationOptions: {
  applyCustomAttributesOnSpan: (span, request) => {
    // Skip internal requests
    if (request.url.includes('/health')) {
      span.setAttribute('skip', true);
    }
  },
}

TypeScript

The package is written in TypeScript and includes type definitions.

import type {
  TracingInstrumentationOptions,
  FaroTraceExporterConfig,
  DefaultInstrumentationsOptions,
} from '@grafana/faro-react-native-tracing';

License

Apache-2.0

Contributing

See the main repository CONTRIBUTING.md for contribution guidelines.

Support