mixpanel-node

repository·master·Indexed 19 days ago

https://github.com/mixpanel/mixpanel-node

A Node.js server-side SDK for Mixpanel that provides event tracking, user profile management via the .people API, and historical event imports. It includes an OpenFeature provider to integrate Mixpanel's feature flags with the OpenFeature Node.js Server SDK, supporting local and remote evaluation strategies.

Tokens
14.9K
Snippets
51
Records
63
Agent score
66%

What's inside mixpanel-node

  1. Configure Evaluation Context

    master

    Context properties are passed directly to Mixpanel for targeting and bucketing. You can set context globally or per-evaluation.

    Note: targetingKey is treated as a standard context property and is not used as a special bucketing key by this provider. Mixpanel's server-side configuration determines which properties are used for targeting.

    Global Context

    await OpenFeature.setProviderAndWait(provider);
    OpenFeature.setContext({ environment: "production" });

    Per-evaluation Context

    Per-evaluation context is merged with and overrides global context.

    const value = await client.getBooleanValue("premium-feature", false, {
      distinct_id: "user-123",
      email: "user@example.com",
      plan: "premium",
      beta_tester: true,
    });
    // Global
    OpenFeature.setContext({ environment: "production" });
    
    // Per-evaluation
    const value = await client.getBooleanValue("flag", false, { distinct_id: "123", plan: "premium" });
  2. Initialize the Mixpanel client

    master

    Use Mixpanel.init("<YOUR_TOKEN>", options) to create a client instance. The library is intended for server-side use and is fully asynchronous.

    Common configuration options include:

    • protocol: Set to "http" to communicate over HTTP instead of HTTPS.
    • keepAlive: Set to false to reestablish the connection on each request.
    • debug: Boolean to enable debug mode.
    • logger: A custom logger instance (e.g., pino, bunyan) that implements the standard logger interface.
    • credentials: An instance of ServiceAccountCredentials for authenticated operations.
    var Mixpanel = require("mixpanel");
    
    // Basic initialization
    var mixpanel = Mixpanel.init("<YOUR_TOKEN>");
    
    // Advanced initialization
    var mixpanel = Mixpanel.init("<YOUR_TOKEN>", {
      protocol: "http",
      keepAlive: false,
      debug: true,
      logger: pinoLogger
    });
  3. Evaluate Mixpanel flags using OpenFeature

    master

    After registering the provider with OpenFeature.setProviderAndWait(provider), use the OpenFeature client to evaluate flags.

    Mapping Mixpanel Flag Types to OpenFeature Methods

    Mixpanel Flag TypeVariant ValuesOpenFeature Method
    Feature Gatetrue / falsegetBooleanValue()
    Experimentboolean, string, number, or JSONgetBooleanValue(), getStringValue(), getNumberValue(), or getObjectValue()
    Dynamic ConfigJSON objectgetObjectValue()

    Example Usage

    import { OpenFeature } from "@openfeature/server-sdk";
    import { MixpanelProvider } from "@mixpanel/openfeature-server-provider";
    
    const provider = MixpanelProvider.createLocal("YOUR_PROJECT_TOKEN");
    await OpenFeature.setProviderAndWait(provider);
    
    const client = OpenFeature.getClient();
    const context = { distinct_id: "user-123" };
    
    // Feature Gate
    const isFeatureOn = await client.getBooleanValue("new-checkout", false, context);
    
    // Experiment (String)
    const buttonColor = await client.getStringValue("button-color-test", "blue", context);
    
    // Experiment (Number)
    const maxItems = await client.getNumberValue("max-items", 10, context);
    
    // Dynamic Config (JSON)
    const featureConfig = await client.getObjectValue("homepage-layout", {}, context);
    import { OpenFeature } from "@openfeature/server-sdk";
    import { MixpanelProvider } from "@mixpanel/openfeature-server-provider";
    
    const provider = MixpanelProvider.createLocal("YOUR_PROJECT_TOKEN");
    await OpenFeature.setProviderAndWait(provider);
    
    const client = OpenFeature.getClient();
    const context = { distinct_id: "user-123" };
    
    const isFeatureOn = await client.getBooleanValue("new-checkout", false, context);
    const buttonColor = await client.getStringValue("button-color-test", "blue", context);
    const maxItems = await client.getNumberValue("max-items", 10, context);
    const featureConfig = await client.getObjectValue("homepage-layout", {}, context);
  4. Initialize the MixpanelProvider

    master

    The MixpanelProvider can be initialized using three different strategies depending on your latency and real-time requirements:

    Evaluates flags locally using cached definitions polled from Mixpanel. This minimizes latency for server-side applications.

    const provider = MixpanelProvider.createLocal("YOUR_PROJECT_TOKEN");

    2. Remote Evaluation

    Makes a network request to Mixpanel for every evaluation. Use this if you need real-time flag values and can tolerate network latency.

    const provider = MixpanelProvider.createRemote("YOUR_PROJECT_TOKEN");

    3. Using an Existing Mixpanel Instance

    If you already have a configured mixpanel instance, you can wrap its existing flags provider. Note that in this mode, provider.mixpanel will be undefined.

    import Mixpanel from "mixpanel";
    
    const mixpanel = Mixpanel.init("YOUR_PROJECT_TOKEN", {
      local_flags_config: {},
    });
    const localFlags = mixpanel.local_flags!;
    localFlags.startPollingForDefinitions();
    
    const provider = new MixpanelProvider(localFlags);
    // Local Evaluation
    const provider = MixpanelProvider.createLocal("YOUR_PROJECT_TOKEN");
    
    // Remote Evaluation
    const provider = MixpanelProvider.createRemote("YOUR_PROJECT_TOKEN");
    
    // Existing Instance
    const provider = new MixpanelProvider(localFlags);
  5. Authenticate using Service Accounts (Recommended)

    master

    Service accounts are the preferred method for server-to-server integrations and provide enhanced security.

    When to use Service Accounts:

    • Importing historical events: Required for events older than 5 days via the .import() endpoint.
    • Server-side feature flags: Required for evaluating feature flags with authentication.

    When Service Accounts are NOT needed:

    • Regular event tracking: .track() only requires the project token.
    • People analytics: .people.set(), .people.increment(), etc., do not require service account authentication.

    Note: API secrets are DEPRECATED and should be migrated to Service Accounts.

    const { ServiceAccountCredentials } = Mixpanel;
    
    const credentials = new ServiceAccountCredentials(
      "YOUR_SERVICE_ACCOUNT_USERNAME",
      "YOUR_SERVICE_ACCOUNT_SECRET",
      "YOUR_PROJECT_ID",
    );
    
    // Initialize with credentials
    var mixpanel = Mixpanel.init("<YOUR_TOKEN>", { credentials });
  6. Identify the source of a feature flag variant

    master

    When evaluating feature flags, the returned variant includes a variant_source field indicating where the value originated. This is useful for debugging whether a flag was served from a local cache, a remote Mixpanel server, or if it fell back to a developer-defined default.

    Available VariantSource values:

    • local: The variant was retrieved from a local evaluation/cache.
    • remote: The variant was retrieved from the Mixpanel backend.
    • fallback: The variant is a developer-defined fallback because the primary evaluation failed.
    // Example of how a variant might look in a response
    const variant = {
      value: 'control',
      variant_source: 'remote'
    };
    
    const fallbackVariant = {
      value: 'control',
      variant_source: 'fallback',
      fallback_reason: { kind: 'FLAG_NOT_FOUND', message: null }
    };
  7. Initialize the Mixpanel OpenFeature Provider

    master

    To use Mixpanel flags with the OpenFeature SDK, you must first create a provider instance using either createLocal or createRemote, and then call initialize().

    • createLocal(token, config): Used for local flag evaluation. It initializes a Mixpanel instance and starts polling for flag definitions.
    • createRemote(token, config): Used for remote flag evaluation (server-side).
    • initialize(context): Captures a global evaluation context and awaits the readiness of the flags provider (e.g., waiting for the first successful fetch of definitions in local mode).
    import { MixpanelProvider } from 'mixpanel-node/openfeature-server-provider';
    
    // For local evaluation
    const provider = MixpanelProvider.createLocal('YOUR_MIXPANEL_TOKEN', { /* LocalFlagsConfig */ });
    
    // Or for remote evaluation
    // const provider = MixpanelProvider.createRemote('YOUR_MIXPANEL_TOKEN', { /* RemoteFlagsConfig */ });
    
    await provider.initialize({ user_id: '123' });
  8. Get full flag resolution details

    master

    To access metadata about a flag evaluation (such as the specific variant or the reason for the value), use getBooleanDetails (or other Details methods). This is useful for debugging or logging.

    const client = OpenFeature.getClient();
    const details = await client.getBooleanDetails("my-feature", false, { distinct_id: "user-123" });
    
    console.log(details.value);    // The resolved value
    console.log(details.variant);  // The variant key from Mixpanel
    console.log(details.reason);   // Why this value was returned
    console.log(details.errorCode); // Error code if evaluation failed
    const details = await client.getBooleanDetails("my-feature", false, { distinct_id: "user-123" });
    console.log(details.value, details.variant, details.reason, details.errorCode);
  9. Track events with mixpanel.track()

    master

    Record user actions by calling .track(event_name, properties).

    Important Mental Model: Unlike client-side libraries, mixpanel-node is stateless and does not use identify(). You must pass the distinct_id within the properties object of every tracking call to associate the event with a user.

    Features:

    • Properties: Pass an object of custom properties.
    • Geolocation: Pass an ip property to get automatic geolocation info.
    • Timestamps: Pass a time property (up to 5 days old). For older events, use .import().
    • Batching: Use .track_batch([...]) to send multiple events in a single request for efficiency.
    • Callbacks: All functions accept an optional callback as the last argument to handle errors.
    // Basic tracking
    mixpanel.track("my event", {
      distinct_id: "some unique client id",
      as: "many",
      properties: "as",
      you: "want",
    });
    
    // Tracking with IP for geolocation
    mixpanel.track("my event", { ip: "127.0.0.1" });
    
    // Tracking with a specific timestamp
    mixpanel.track("timed event", { time: new Date() });
    
    // Batch tracking
    mixpanel.track_batch([
      {
        event: "recent event",
        properties: {
          time: new Date(),
          distinct_id: "billybob",
          gender: "male",
        },
      },
      {
        event: "another recent event",
        properties: {
          distinct_id: "billybob",
          color: "red",
        },
      },
    ]);
    
    // Using a callback
    mixpanel.track("test", function (err) {
      if (err) throw err;
    });
  10. Access the underlying Mixpanel instance

    master

    If you initialized the provider using createLocal or createRemote, you can access the underlying Mixpanel instance via provider.mixpanel to perform manual tracking or profile updates.

    Note: This property is undefined if the provider was constructed by passing an existing flags provider directly.

    const mixpanel = provider.mixpanel;
    if (mixpanel) {
      mixpanel.track("button_clicked", { distinct_id: "user-123" });
    }
    const mixpanel = provider.mixpanel;
    if (mixpanel) {
      mixpanel.track("event_name", { distinct_id: "user-123" });
    }