Skip to content

Quick start: React Native

On this page you send your first event and see it in your app's log. You don't need an account with any analytics service yet: you start with Herald's log module, which prints each event instead of sending it. At the end you add Firebase.

Add the core library and the log module. The React Native SDK page lists all the modules.

npm install @herald-analytics/core @herald-analytics/log

1. Describe what happened

An event is a small class in your app. It has a name, and parameters that describe what happened:

export class CheckoutStarted implements Event {
  readonly name = 'checkout_started';

  constructor(
    readonly plan: string,
    readonly seats: number,
  ) {}

  get parameters(): EventParameters {
    return { plan: this.plan, seats: int(this.seats) };
  }
}

Parameters keep their type. seats reaches every service as the number 3, not as the text "3", so you can still sum and filter by it there.

2. Create Herald

Herald is the object your app talks to. You give it the services to send to, and it passes every event on to each of them. Herald calls these services providers.

Here there's one provider, the log module. It has two parts: a tracker that handles events and user properties, and a service that handles everything else, such as start-up and sign-in.

// Where the log lines go: the console fits as-is.
const logger: AnalyticsLogger = (message) => console.log(message);

// Handles events and user properties, using Herald's ready-made factories.
const logTracker = new LogAnalyticsTrackerService({
  eventTrackerFactory: new CompositeLogEventTrackerFactory([
    new ScreenViewLogEventTrackerFactory(logger), // screen views
    new GenericLogEventTrackerFactory(logger), // every other event
  ]),
  propertySetterFactory: new CompositeLogPropertySetterFactory([
    new GenericLogPropertySetterFactory(logger),
  ]),
});
// Handles the rest: start-up, sign-in and sign-out, consent.
const logService = new LogAnalyticsService(logger);

const herald = new Herald({
  providers: [
    new HeraldProvider({
      name: 'log',
      events: logTracker,
      properties: logTracker,
      identity: logService,
      lifecycle: logService,
      consent: logService,
    }),
  ],
});

Create Herald once for the whole app. Set up your app shows how to share it.

Start it in the app's entry file, which runs once each time the app starts. start() returns a promise, because some services set themselves up in the background:

// In the app's entry file, which runs once each time the app starts.
const herald = createHerald();
herald.start(); // Herald reports a vendor that fails, so there's nothing to catch

AppRegistry.registerComponent('main', () => () => <App analytics={herald} />);

With Expo Router, create Herald in a module of its own and start it there: the root layout imports it, so it runs once when the app starts.

3. Track the event

Your classes don't use Herald directly. They ask for EventTrackerService, a small interface with a single track function, and you pass Herald in its place. That keeps them easy to test: in tests you pass a fake instead.

export class CheckoutViewModel {
  constructor(private readonly analytics: EventTrackerService) {}

  onCheckout(plan: string, seats: number): Promise<void> {
    return this.analytics.track(new CheckoutStarted(plan, seats));
  }
}

Call onCheckout('pro', 3), and the log shows the event as a real service would receive it:

Metro
 LOG  [herald] start
 LOG  [herald] event   checkout_started
    ├─ plan  = pro
    └─ seats = 3

4. Add Firebase

First set up Firebase in your app the usual way, by following React Native Firebase's guide. Then add Herald's Firebase module:

npm install @herald-analytics/firebase

The Firebase provider is built the same way as the log one. Its factories send screen views as GA4's own screen_view event, and every other event under its own name:

export function firebaseProvider(firebaseAnalytics: Analytics): HeraldProvider {
  const tracker = new FirebaseAnalyticsTrackerService({
    eventTrackerFactory: new CompositeFirebaseEventTrackerFactory([
      new ScreenViewFirebaseEventTrackerFactory(firebaseAnalytics), // GA4's reserved screen_view
      new GenericFirebaseEventTrackerFactory(firebaseAnalytics), // everything else, as-is
    ]),
    propertySetterFactory: new CompositeFirebasePropertySetterFactory([
      new GenericFirebasePropertySetterFactory(firebaseAnalytics),
    ]),
  });
  const service = new FirebaseAnalyticsService(firebaseAnalytics);
  return new HeraldProvider({
    name: 'firebase',
    events: tracker,
    properties: tracker,
    identity: service,
    lifecycle: service,
    consent: service,
  });
}

Add it to Herald next to the log provider:

const herald = new Herald({
  providers: [
    new HeraldProvider({
      name: 'log',
      events: logTracker,
      properties: logTracker,
      identity: logService,
      lifecycle: logService,
      consent: logService,
    }),
    firebaseProvider(firebaseAnalytics), // the new line
  ],
});

The same CheckoutStarted now goes to both the log and Firebase, and CheckoutViewModel didn't change at all.

Next

  • Set up your app: several services, error reporting and dependency injection.
  • React Native SDK: every module, and what's specific to React Native.
  • React: screen views and impressions from components.
  • Philosophy: why Herald works the way it does.