Skip to content

Mixpanel

Herald's Mixpanel module sends events to Mixpanel with typed properties. It covers both places where Mixpanel keeps attributes:

  • the people profile, which describes a person;
  • super properties, which are sent with every event.
SDK Package
Android io.github.mkhytarmkhoian:herald-mixpanel
Flutter herald_mixpanel, over mixpanel_flutter
iOS herald-ios-mixpanel, module HeraldMixpanel, over mixpanel-swift
React Native @herald-analytics/mixpanel, over mixpanel-react-native

Setup

You create the MixpanelAPI, the Mixpanel on Flutter and React Native, or the MixpanelInstance on iOS: token, options, server URL for data residency. Herald never changes them.

val mixpanel = MixpanelAPI.getInstance(
    context,
    projectToken,
    false, // trackAutomaticEvents
    MixpanelOptions.Builder().optOutTrackingDefault(true).build(), // silent until consent
)

val tracker = MixpanelAnalyticsTrackerService(
    CompositeMixpanelEventTrackerFactory(
        ScreenViewMixpanelEventTrackerFactory(mixpanel),
        GenericMixpanelEventTrackerFactory(mixpanel),
    ),
    CompositeMixpanelPropertySetterFactory(
        UserPropertyMixpanelPropertySetterFactory(mixpanel), // people profile: must come first
        GenericMixpanelPropertySetterFactory(mixpanel),      // super properties
    ),
)
val service = MixpanelAnalyticsService(mixpanel)

val provider = Herald.Provider(
    name = "mixpanel",
    events = tracker,
    properties = tracker,
    identity = service,
    lifecycle = service,
    consent = service,
)
let mixpanel = Mixpanel.initialize(
    token: projectToken,
    trackAutomaticEvents: false,
    optOutTrackingByDefault: true  // silent until consent
)

let tracker = MixpanelAnalyticsTrackerService(
    eventTrackerFactory: CompositeMixpanelEventTrackerFactory([
        ScreenViewMixpanelEventTrackerFactory(mixpanel: mixpanel),
        GenericMixpanelEventTrackerFactory(mixpanel: mixpanel),
    ]),
    propertySetterFactory: CompositeMixpanelPropertySetterFactory([
        UserPropertyMixpanelPropertySetterFactory(mixpanel: mixpanel),  // the profile: first
        GenericMixpanelPropertySetterFactory(mixpanel: mixpanel),  // super properties
    ])
)
let service = MixpanelAnalyticsService(mixpanel: mixpanel)

let provider = HeraldProvider(
    name: "mixpanel",
    events: tracker,
    properties: tracker,
    identity: service,
    lifecycle: service,
    consent: service
)
final mixpanel = await Mixpanel.init(
  projectToken,
  trackAutomaticEvents: false,
  optOutTrackingDefault: true, // silent until consent
);

final tracker = MixpanelAnalyticsTrackerService(
  eventTrackerFactory: CompositeMixpanelEventTrackerFactory([
    ScreenViewMixpanelEventTrackerFactory(mixpanel),
    GenericMixpanelEventTrackerFactory(mixpanel),
  ]),
  propertySetterFactory: CompositeMixpanelPropertySetterFactory([
    UserPropertyMixpanelPropertySetterFactory(mixpanel), // people profile: must come first
    GenericMixpanelPropertySetterFactory(mixpanel), // super properties
  ]),
);
final service = MixpanelAnalyticsService(mixpanel);

final provider = HeraldProvider(
  name: 'mixpanel',
  events: tracker,
  properties: tracker,
  identity: service,
  lifecycle: service,
  consent: service,
);
const mixpanel = await Mixpanel.init(
  projectToken,
  false, // no automatic events
  true, // opted out by default: silent until consent
);

const tracker = new MixpanelAnalyticsTrackerService({
  eventTrackerFactory: new CompositeMixpanelEventTrackerFactory([
    new ScreenViewMixpanelEventTrackerFactory(mixpanel),
    new GenericMixpanelEventTrackerFactory(mixpanel),
  ]),
  propertySetterFactory: new CompositeMixpanelPropertySetterFactory([
    new UserPropertyMixpanelPropertySetterFactory(mixpanel), // people profile: must come first
    new GenericMixpanelPropertySetterFactory(mixpanel), // super properties
  ]),
});
const service = new MixpanelAnalyticsService(mixpanel);

const provider = new HeraldProvider({
  name: 'mixpanel',
  events: tracker,
  properties: tracker,
  identity: service,
  lifecycle: service,
  consent: service,
});

What reaches Mixpanel

Herald Mixpanel
an event trackMap(name, properties), with each value as its own JSON type
a ScreenViewEvent trackMap("screen_view") with its name as screen_name, sent by ScreenViewMixpanelEventTrackerFactory; a screen view with its own screen_name parameter is refused and reported
a UserProperty people.set(name, value): the person's profile
any other property a super property, sent with every later event
identify / reset identify(userId, true) / reset()
start nothing: set Mixpanel's logging on the MixpanelAPI yourself, as its docs describe
flush flush()
setEnabled(true) / setEnabled(false) optInTracking() / flush() then optOutTracking()
Herald Mixpanel
an event track(event:properties:), with each value as its own type
a ScreenViewEvent track(event: "screen_view") with its name as screen_name, sent by ScreenViewMixpanelEventTrackerFactory; a screen view with its own screen_name parameter is refused and reported
a UserProperty people.set(property:to:): the person's profile
any other property registerSuperProperties: sent with every later event
identify / reset identify(distinctId: userId) / reset()
start nothing: turn on Mixpanel's logging yourself, as its docs describe
flush flush()
setEnabled(true) / setEnabled(false) optInTracking() / flush() then optOutTracking()
Herald Mixpanel
an event track(name, properties:), with each value as its own JSON type
a ScreenViewEvent track('screen_view') with its name as screen_name, sent by ScreenViewMixpanelEventTrackerFactory; a screen view with its own screen_name parameter is refused and reported
a UserProperty getPeople().set(name, value): the person's profile
any other property registerSuperProperties: sent with every later event
identify / reset identify(userId) / reset()
start nothing: turn on Mixpanel's logging yourself, as its docs describe
flush flush()
setEnabled(true) / setEnabled(false) optInTracking() / flush() then optOutTracking()
Herald Mixpanel
an event track(name, properties), with each value as its own JSON type
a ScreenViewEvent track('screen_view') with its name as screen_name, sent by ScreenViewMixpanelEventTrackerFactory; a screen view with its own screen_name parameter is refused and reported
a UserProperty getPeople().set(name, value): the person's profile
any other property registerSuperProperties: sent with every later event
identify / reset identify(userId) / reset()
start nothing: turn on Mixpanel's logging yourself, as its docs describe
flush flush()
setEnabled(true) / setEnabled(false) optInTracking() / flush() then optOutTracking()

Factories

Factory Handles
ScreenViewMixpanelEventTrackerFactory every ScreenViewEvent, as one screen_view event broken down by screen
GenericMixpanelEventTrackerFactory everything else; usually last in the chain
UserPropertyMixpanelPropertySetterFactory every UserProperty
GenericMixpanelPropertySetterFactory every property, as a super property
RequireMappedMixpanelEventTrackerFactory, RequireMappedMixpanelPropertySetterFactory nothing: throws for anything that reaches it

Order the property chain

UserPropertyMixpanelPropertySetterFactory must come before the generic setter. A UserProperty is also a Property, so the generic setter would take it first, and the profile would never be written. A UserProperty goes to the profile only. To put a value in both places, write a factory that answers with both setters.

A fresh install collects unless Mixpanel is created opted out: MixpanelOptions.Builder().optOutTrackingDefault(true) on Android, Mixpanel.init(token, optOutTrackingDefault: true, ...) on Flutter, Mixpanel.initialize(token:trackAutomaticEvents:optOutTrackingByDefault: true) on iOS, or Mixpanel.init(token, trackAutomaticEvents, true) on React Native.

Herald can't opt out for you in start(). optOutTracking() deletes events not yet sent and the stored user, so calling it on every launch would throw away the previous session and forget a user who had already agreed. Once the user agrees, Mixpanel remembers it. On iOS, opting out also deletes the identified user's People profile in Mixpanel: that's Mixpanel's own behaviour.

Identity

To never identify users in Mixpanel, register the Mixpanel provider without identity.

Watch out for

  • Mixpanel bills per event. Screen views and high-frequency events add up. Drop what you don't need in Mixpanel's chain; Routing shows how. Moove drops screen views for Mixpanel entirely.