# Kissmetrics

- Tool: FlutterFlow
- Difficulty: Intermediate
- Time required: 2 hours
- Last updated: July 2026

## TL;DR

Connect FlutterFlow to Kissmetrics by creating FlutterFlow API Calls that POST to the Kissmetrics HTTP tracking API endpoints — `/e` for events, `/s` for person properties, and `/a` to alias anonymous users to real identities. Because Kissmetrics has no Flutter SDK, route all three calls through a Firebase Cloud Function or Supabase Edge Function that adds your write-only tracking key server-side and queues events for offline resilience.

## Person-Based Event Tracking in FlutterFlow with Kissmetrics

Kissmetrics takes a different approach from pageview-centric analytics tools: every event is permanently tied to a person, not a session. That makes it powerful for SaaS and e-commerce funnel analysis — you can answer questions like 'of users who signed up in January, what percentage completed a purchase within 30 days?' But that power depends entirely on getting the person identity (`_p`) right. On mobile, where users launch and kill apps constantly, generating a new `_p` on every launch is the single most common integration mistake — it inflates your user count, breaks funnel continuity, and makes cohort data meaningless. This tutorial makes persistent identity the centerpiece.

The good news is that the Kissmetrics HTTP tracking API is one of the simplest in analytics. You do not need an SDK. Three endpoints on `https://trk.kissmetrics.io` cover everything: `/e` records a named event with optional properties, `/s` sets person properties without an event, and `/a` aliases one identifier to another (the anonymous-to-identified stitch). Each call is a GET or POST with your tracking key (`_k`) and person ID (`_p`) as query parameters. This maps cleanly to FlutterFlow API Calls — no Custom Action or pub.dev package required for the core integration.

A note on platform maturity: Kissmetrics is a legacy tool that has changed ownership multiple times and has a declining market presence. Before investing engineering time in this integration, confirm your account is active and that the API endpoints respond. If you are evaluating analytics platforms for a new FlutterFlow app, consider Mixpanel or Amplitude as modern successors — they offer equivalent person-based analytics with active Flutter SDKs and maintained documentation. This tutorial is for teams already using Kissmetrics who need their FlutterFlow app to send data into an existing Kissmetrics account.

## Before you start

- An active Kissmetrics account with a product created — note your write-only tracking API key from the product settings
- A FlutterFlow project on a paid plan (API Calls are available on paid plans)
- A Firebase project with Cloud Functions (Blaze plan) or a Supabase project to host the proxy function
- A basic understanding of FlutterFlow App State for storing the persistent person identifier across sessions
- Confirmation that your Kissmetrics account and API endpoints are still active — the platform is legacy and has had service interruptions

## Step-by-step guide

### 1. Get your Kissmetrics tracking API key and understand the three endpoints

Log into your Kissmetrics account and navigate to the product you want to track. In the product settings, locate the tracking API key — it is a long alphanumeric string like `abc123def456...`. This key is write-only: anyone who has it can send events to your Kissmetrics account, but they cannot read your data. For a prototype you could use it directly in FlutterFlow API Call query parameters, but because it is embedded in the compiled app bundle and can be extracted from the APK or IPA, the production recommendation is to hold it server-side in a proxy.

Before building anything in FlutterFlow, understand the three API endpoints you will use. All three live on the base URL `https://trk.kissmetrics.io` and accept either GET (query params) or POST (form data). The `/e` endpoint records a named event: required params are `_k` (your API key), `_p` (person identifier), and `_n` (event name); optional params are additional event properties like `productId` or `planType`. The `/s` endpoint sets person properties without recording an event: same `_k` and `_p`, plus any key-value pairs you want to set on the person (like `plan: 'trial'` or `country: 'US'`). The `/a` endpoint aliases two person identifiers together: params are `_k`, `_p` (the identity to keep — typically the real user ID), and `_n` (the identity being aliased — typically the anonymous ID). Call `/a` exactly once when a user creates an account or signs in, to stitch their anonymous history to their permanent account identity.

Write down your API key and the three endpoint paths — you will use them in the proxy and the FlutterFlow API Calls in the next steps.

```
// Kissmetrics HTTP Tracking API — endpoint summary
// Base URL: https://trk.kissmetrics.io
//
// Record an event:
// GET /e?_k={apiKey}&_p={personId}&_n={eventName}&{optionalProps}
//
// Set person properties:
// GET /s?_k={apiKey}&_p={personId}&{propertyKey}={propertyValue}
//
// Alias two identities (call once at sign-in):
// GET /a?_k={apiKey}&_p={realUserId}&_n={anonymousId}
```

**Expected result:** You have your API key written down and understand the purpose of the three endpoint paths (`/e`, `/s`, `/a`). You can mentally model which endpoint fires at which user action in your app.

### 2. Deploy a Firebase or Supabase proxy to hold the API key server-side

Although the Kissmetrics tracking key is write-only, embedding it in the compiled Flutter app bundle exposes it to anyone who decompiles the APK or IPA — a scraped write key can be used to inject thousands of fake events into your Kissmetrics account, corrupting all your funnel data. For production apps, route the three Kissmetrics calls through a lightweight backend proxy that holds the key as an environment variable and is never exposed to the client.

For a Firebase Cloud Function proxy: in the Firebase Console, enable Cloud Functions on the Blaze plan, then create a new function. Store your Kissmetrics API key as a secret using `firebase functions:secrets:set KISSMETRICS_API_KEY` in a terminal on your machine (not in FlutterFlow — this is a one-time server setup step). The function accepts a JSON body from FlutterFlow with three fields: `endpoint` (one of `e`, `s`, or `a`), `person` (the `_p` value), and `params` (an object of additional query parameters like event name or property key-values). It then constructs the full Kissmetrics URL with the key from the environment, makes the outbound HTTP call to `trk.kissmetrics.io`, and returns the result to FlutterFlow.

For Supabase Edge Functions: create an Edge Function in your Supabase project dashboard → Edge Functions → New Function, name it `kissmetrics-proxy`, and set the `KISSMETRICS_API_KEY` secret in the Supabase dashboard under Settings → Edge Functions → Secrets. The Deno function accepts the same JSON body shape. In both cases, add CORS headers so web builds of your FlutterFlow app can reach the proxy from a browser.

Deploy the function and copy its HTTPS endpoint URL — this is the only URL that goes into FlutterFlow. Never put the Kissmetrics API key in a FlutterFlow API Call header or query param directly.

```
// Firebase Cloud Function proxy — index.js
const functions = require('firebase-functions');
const axios = require('axios');

const KM_KEY = process.env.KISSMETRICS_API_KEY;
const KM_BASE = 'https://trk.kissmetrics.io';

exports.kissmetricsProxy = functions.https.onRequest(async (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');
  res.set('Access-Control-Allow-Headers', 'Content-Type');
  if (req.method === 'OPTIONS') { res.status(204).send(''); return; }

  const { endpoint, person, params = {} } = req.body;
  if (!endpoint || !person) {
    return res.status(400).json({ error: 'Missing endpoint or person' });
  }

  const queryParams = new URLSearchParams({
    _k: KM_KEY,
    _p: person,
    ...params,
  });

  try {
    const kmRes = await axios.get(`${KM_BASE}/${endpoint}?${queryParams.toString()}`);
    res.json({ status: kmRes.status, data: kmRes.data });
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});
```

**Expected result:** Your proxy function is deployed and accessible at an HTTPS endpoint. Calling it with a test JSON body `{"endpoint":"e","person":"test123","params":{"_n":"Test Event"}}` returns a 200 response and the event appears in your Kissmetrics account.

### 3. Generate and persist a stable `_p` person identifier on first app launch

The single most important detail in a Kissmetrics mobile integration is the `_p` person identifier. It must be: (1) unique per person, (2) stable across app launches, sessions, and app updates, and (3) replaced with the real user ID at sign-in via the `/a` alias call. If you generate a new UUID every time the app opens, every launch looks like a new user — your user count explodes and all funnel data becomes meaningless.

In FlutterFlow, the approach is to use a combination of App State and a Supabase or Firestore record (or at minimum, Flutter's local storage via a Custom Action) to persist the identifier. Here is the recommended flow: when the app opens, check an App State variable called `kmPersonId` — if it is empty (first launch), generate a UUID string (FlutterFlow has a built-in `generateRandomString` or you can use a Custom Action that calls `const uuid = Uuid()` from the `uuid` pub.dev package), store it in App State, and also write it to Firestore/Supabase under the user's anonymous session document so it survives an app reinstall on a known device. On subsequent launches, check App State first; if empty (reinstall on a new device without Firestore recovery), generate a new one.

To set this up in FlutterFlow: go to App State → + Add Field → Name: `kmPersonId`, Type: String, Initial Value: empty string. On your app's root page or the initial splash screen, in the Actions panel → On Page Load, add a conditional action: if `kmPersonId` is empty → generate UUID → update App State `kmPersonId`. Wire this before any event-tracking calls. Make `kmPersonId` a Persisted App State variable if your FlutterFlow version supports it, which writes it to the device's local storage automatically. This persisted variable survives app restarts without requiring a Firestore write — the simplest production solution.

```
// Custom Action: generateKmPersonId.dart
// Use only if FlutterFlow's built-in string generation is insufficient
// Requires adding 'uuid: ^4.0.0' in Dependencies field
import 'package:uuid/uuid.dart';

Future<String> generateKmPersonId() async {
  const uuid = Uuid();
  return uuid.v4(); // e.g. '550e8400-e29b-41d4-a716-446655440000'
}
```

**Expected result:** On first launch, `kmPersonId` in App State is populated with a stable UUID. On subsequent launches (tested by closing and reopening the app), the same UUID persists. No two separate app opens produce the same UUID for different devices.

### 4. Add FlutterFlow API Groups and API Calls for the three Kissmetrics endpoints

With the proxy deployed and the person ID generation working, set up the FlutterFlow API Calls. In the left nav, click API Calls → + Add → Create API Group. Name it `KissmetricsProxy`. Set the base URL to your deployed Firebase Cloud Function or Supabase Edge Function HTTPS endpoint (e.g., `https://us-central1-your-project.cloudfunctions.net/kissmetricsProxy`). Leave the Headers section at the default `Content-Type: application/json` — no API key in headers, since the proxy handles authentication internally.

Now add three API Calls inside the group. First, click + Add Call → name it `RecordEvent` → set method to POST → set the body to: `{ "endpoint": "e", "person": "{{ personId }}", "params": { "_n": "{{ eventName }}", "{{ propKey1 }}": "{{ propValue1 }}" } }`. Add variables for `personId` (bound to App State `kmPersonId`), `eventName` (a string you'll hardcode per action), and optional property variables. Second, add a call named `SetPersonProperty` → POST → body: `{ "endpoint": "s", "person": "{{ personId }}", "params": { "{{ propertyKey }}": "{{ propertyValue }}" } }`. Third, add `AliasIdentity` → POST → body: `{ "endpoint": "a", "person": "{{ realUserId }}", "params": { "_n": "{{ anonymousId }}" } }` — the `_p` here is the real user ID to keep, and `_n` is the anonymous UUID being merged.

For each API Call, click Response & Test, paste the proxy's success response `{"status": 200, "data": ""}`, and generate JSON Paths. The Kissmetrics tracking API returns minimal responses (usually just an empty body or a pixel), so you do not need to create a Data Type for these — you just fire-and-forget. In the Action Flow Editor for each widget that should track an event (e.g., a 'Purchase' button), add the action: Backend/API Calls → `RecordEvent` → bind `personId` to App State `kmPersonId` → set `eventName` to the hardcoded event string (e.g., `'Purchase Completed'`).

```
// FlutterFlow API Call body for RecordEvent
{
  "endpoint": "e",
  "person": "{{ personId }}",
  "params": {
    "_n": "{{ eventName }}",
    "plan": "{{ planType }}",
    "amount": "{{ purchaseAmount }}"
  }
}

// FlutterFlow API Call body for AliasIdentity (fire once at sign-in)
{
  "endpoint": "a",
  "person": "{{ realUserId }}",
  "params": {
    "_n": "{{ anonymousId }}"
  }
}
```

**Expected result:** All three API Calls appear in your KissmetricsProxy API Group in FlutterFlow. Testing RecordEvent via Response & Test with a real `personId` and `eventName` returns a 200 status and the event appears in your Kissmetrics live activity stream within a few seconds.

### 5. Wire the alias call at sign-in and fire events at key app moments

The alias call is the most critical event in the entire Kissmetrics integration — it is what stitches the anonymous person ID collected before login to the user's real, permanent account identity. You must fire it exactly once, at the moment the user creates an account or signs in for the first time. Do not fire it on every login — aliasing is idempotent in Kissmetrics but repeated alias calls for the same pair can create unexpected person merges in some account configurations.

In FlutterFlow's Action Flow Editor, locate the action sequence that runs after a successful sign-in or account creation. After the authentication success step (Supabase Auth → Sign In, Firebase Auth → Sign In, or your custom auth action), add a Backend/API Call → `AliasIdentity`. Bind `realUserId` to the authenticated user's unique ID (from Supabase's `currentUserUid`, Firebase's `currentUserUID`, or your own user record). Bind `anonymousId` to App State `kmPersonId`. After the alias fires, update App State `kmPersonId` to the real user ID — from this point forward, all events should use the real user ID as `_p` so they continue on the same person timeline. Add a conditional check before the alias call: only fire it if App State `anonIdAliased` is false, then set `anonIdAliased` to true — this guards against re-aliasing on every subsequent login.

For event tracking, wire `RecordEvent` calls to key moments: app open (App Launched), completing onboarding steps (Onboarding Step 1 Completed), first feature use (Feature X Used), subscription start (Subscription Started), and purchase (Purchase Completed). Use the `SetPersonProperty` call to set metadata when it changes — for example, after a user upgrades their plan, fire `/s` with `plan: 'pro'` so Kissmetrics can filter funnels by plan tier.

To build offline resilience, store pending events in an App State list (array of JSON-like strings) and flush the list to the proxy in a batch on app resume or on a timer, rather than firing one live API Call per tap. For a RapidDev implementation of this identity-proxy architecture with offline queuing, see rapidevelopers.com/contact for a free scoping call.

**Expected result:** On sign-in, the alias API Call fires and Kissmetrics merges the anonymous person's event history with the real user ID. In the Kissmetrics People view, you can find the user by their real ID and see all events from both before and after sign-in in one timeline.

### 6. Queue events for offline resilience and validate in Kissmetrics Live

Mobile networks are unreliable. If your FlutterFlow app fires one live HTTP call per user tap and the user is on a poor connection, events drop silently — there is no retry mechanism built into a FlutterFlow API Call. The solution is to batch-queue events in App State and flush them periodically or on app resume.

Create an App State variable `kmEventQueue` of type JSON (or a list of strings representing serialized event objects). Each event-triggering action in the Action Flow Editor should first append the event to `kmEventQueue` rather than immediately calling the API. On app resume (Page Load action on your root page) and on a periodic timer (use a Timer action or a scheduled loop), take the first N items from the queue, loop through them calling `RecordEvent` for each, and on success remove them from the queue. This pattern means a user who taps through ten features while offline will have all ten events land in Kissmetrics the next time they connect.

For simpler implementations (prototype or low-traffic apps), skipping the queue and firing directly is acceptable — just be aware that events may drop on flaky connections. If you see gaps in your Kissmetrics funnel that do not match your app's actual usage, dropped events from poor connectivity are the most likely cause.

To validate the full integration: open your Kissmetrics account and navigate to the Live Stream or Activity view. Open your FlutterFlow app on a real device (or in a Run Mode build), trigger a few events — sign up flow, button taps, navigation — and watch them appear in the Live Stream within seconds. Confirm that: (1) the person identifier is stable across multiple interactions, (2) the alias event appears when you sign in, (3) event names match what you set in the API Calls, and (4) properties are attached to the events correctly. Once validated on a real device, your Kissmetrics integration is production-ready.

**Expected result:** Events from your FlutterFlow app appear in the Kissmetrics Live Stream with the correct person ID, event names, and properties. The alias event correctly merges the anonymous person record with the signed-in user's ID. Events queued while offline are flushed and appear in Kissmetrics on next connection.

## Best practices

- Always persist the `_p` person identifier using FlutterFlow Persisted App State (or Firestore/Supabase as a fallback) — regenerating it on each launch is the single most damaging mistake in a Kissmetrics mobile integration.
- Fire the `/a` alias call exactly once at sign-in or account creation, then immediately update App State `kmPersonId` to the real user ID so all subsequent events use the permanent identity.
- Route all three Kissmetrics API Calls through a backend proxy (Firebase Cloud Function or Supabase Edge Function) that holds the tracking key server-side, even though the key is write-only — a scrapeable key enables fake-event injection that corrupts funnel data.
- Queue events in App State and flush in batches rather than firing one live API Call per user action — mobile networks drop individual calls silently, causing gaps in funnels that look like real drop-off.
- Keep event names consistent, human-readable, and agreed on with your analytics team before launch — Kissmetrics uses the exact event name string as the funnel step identifier, and renaming events post-launch breaks historical funnels.
- Add a GDPR/CCPA consent gate before initializing any event tracking — check a consent App State flag before firing any Kissmetrics API Calls, and provide an opt-out mechanism in your app settings.
- Confirm your Kissmetrics account is still active and the API endpoints respond before investing implementation time — the platform has had service disruptions and ownership changes; validate with a test event first.
- If migrating to a modern analytics platform, consider routing events to both Kissmetrics and Mixpanel or Amplitude in parallel during the transition period so historical cohort data is preserved in Kissmetrics while new data builds up in the successor platform.

## Use cases

### SaaS app tracking trial-to-paid conversion funnel

A B2B SaaS product built with FlutterFlow tracks every step from anonymous sign-up through feature usage to paid plan activation. On first launch an anonymous `_p` is generated; at email sign-up `/a` aliases it to the user's email so the trial and paid journeys stitch into one person timeline. The `/e` call fires on feature-use events so the team can identify which features correlate with conversion.

Prompt example:

```
Build a FlutterFlow SaaS app that sends a Kissmetrics event on first app open (anonymous ID), aliases to user email at sign-up, tracks feature-usage events, and records a Signed Up for Paid Plan event on subscription.
```

### E-commerce app measuring product discovery to purchase

A consumer shopping app records product view, add-to-cart, and purchase events per person so the marketing team can build Kissmetrics funnels showing where mobile shoppers drop off. Each event carries product metadata (productId, category, price) as additional properties. The stable `_p` ties all events to one shopper even across multiple sessions and devices after the alias call at login.

Prompt example:

```
Create a FlutterFlow shopping app that fires Kissmetrics events for Product Viewed, Added to Cart, and Purchase Completed with product metadata, using a persistent person ID that aliases to the user's account ID at login.
```

### Onboarding funnel analysis for a FlutterFlow mobile app

A consumer app with a multi-step onboarding flow uses Kissmetrics to measure completion rates at each step. An event fires on each screen (Onboarding Step 1 Viewed, Step 2 Viewed, Profile Setup Completed) so product managers can see exactly which step causes the most drop-off. The anonymous `_p` is set on first launch so even users who abandon before creating an account appear in the funnel.

Prompt example:

```
Build a FlutterFlow app that fires a Kissmetrics event on each onboarding screen with a step number property, using an anonymous person ID so funnel completion is tracked even for users who never create an account.
```

## Troubleshooting

### User count in Kissmetrics is growing 5-10x faster than actual sign-ups — thousands of unknown persons with a handful of events each

Cause: The `_p` person identifier is being regenerated on every app launch or page load instead of being persisted. This is the #1 Kissmetrics mobile integration mistake — each new `_p` creates a new person record in Kissmetrics even if it is the same physical user.

Solution: Go to FlutterFlow App State → find `kmPersonId` → ensure it is marked as Persisted (so it survives app restarts). Remove any logic that resets or regenerates `kmPersonId` on page load. The generation logic (Step 3) should only run when `kmPersonId` is empty, not on every launch. If you have already generated duplicate person records, they cannot easily be merged — fix the root cause first to stop new duplicates, then contact Kissmetrics support about data cleanup options.

### Proxy returns 400 Bad Request or the Kissmetrics Live Stream shows no events after firing

Cause: The JSON body sent from FlutterFlow to the proxy is malformed — either the `endpoint`, `person`, or `params` field is missing or uses an unexpected type, or the FlutterFlow variable binding is resolving to an empty string because `kmPersonId` was not populated before the API Call fired.

Solution: In the FlutterFlow API Call → Response & Test tab, manually enter the body with hardcoded test values (e.g., `{"endpoint":"e","person":"test-user-123","params":{"_n":"Test Event"}}`) and run the test. If that succeeds but the live call fails, the variable bindings are the issue — check that `kmPersonId` is populated before the event fires by adding a conditional that skips the API Call if `kmPersonId` is empty. In the proxy Cloud Function logs, check for the exact error message from Kissmetrics (`trk.kissmetrics.io` returns a 200 even for malformed requests, so check the proxy's own validation logic).

### XMLHttpRequest error when testing Kissmetrics API Calls in FlutterFlow web preview or web build

Cause: The Kissmetrics tracking endpoint `https://trk.kissmetrics.io` may not include CORS headers that allow browser requests from your FlutterFlow app's preview or web build origin. The browser enforces CORS on web; native mobile builds do not have this restriction.

Solution: This is exactly why routing through your own proxy is recommended — your Firebase Cloud Function or Supabase Edge Function adds `Access-Control-Allow-Origin: *` to its responses, so the browser can reach your proxy even if `trk.kissmetrics.io` blocks direct browser requests. If you were calling Kissmetrics directly (without a proxy) and see this error on web, switch to the proxy pattern described in Step 2. On native iOS/Android builds, this error does not occur.

```
// Add to your Cloud Function / Edge Function response:
res.set('Access-Control-Allow-Origin', '*');
res.set('Access-Control-Allow-Headers', 'Content-Type');
```

### Kissmetrics funnel shows a gap after the alias event — events before and after sign-in appear as two separate people despite calling `/a`

Cause: The alias call fired correctly but App State `kmPersonId` was not updated to the real user ID after aliasing. All events after sign-in still used the old anonymous UUID as `_p`, so they appear as a separate (already-aliased) person rather than continuing on the real user's timeline.

Solution: After the `AliasIdentity` API Call fires successfully in the Action Flow Editor, add an Update App State action → set `kmPersonId` to the authenticated user's real ID (from currentUserUid or your user record). From that point forward all `/e` and `/s` calls use the real ID as `_p`. You can verify this worked by finding the user in Kissmetrics People by real user ID and confirming both the pre-login and post-login events appear in one unified timeline.

## Frequently asked questions

### Does Kissmetrics have an official Flutter or Dart SDK?

No — Kissmetrics does not publish an official Flutter or Dart SDK. The integration uses FlutterFlow API Calls that POST directly to the Kissmetrics HTTP tracking API (or to a backend proxy in front of it). This is actually an advantage in terms of FlutterFlow compatibility, since the simple HTTP API works without Custom Actions or pub.dev packages, making it one of the simpler analytics integrations in this category.

### Is the Kissmetrics tracking API key safe to put directly in a FlutterFlow API Call?

The key is write-only — it cannot be used to read your Kissmetrics data. However, embedding it in the compiled Flutter app bundle means anyone who decompiles your APK or IPA can extract it and use it to inject fake events into your account, corrupting your funnel and cohort data. For production apps, the recommended approach is to route all three API Calls through a Firebase Cloud Function or Supabase Edge Function that holds the key as an environment secret.

### Why do I keep seeing 'Unknown Person' entries with only one or two events each in Kissmetrics?

This is almost always caused by the `_p` person identifier being regenerated on each app launch instead of being persisted. Each new UUID creates a new person record in Kissmetrics. Fix it by making your FlutterFlow App State variable `kmPersonId` a Persisted variable (writes to device local storage) and ensuring the UUID generation logic only runs when `kmPersonId` is empty, not on every page load or app open.

### Should I use GET or POST for the Kissmetrics tracking endpoints?

The Kissmetrics HTTP API accepts both GET (query parameters) and POST (form-encoded body). For FlutterFlow API Calls routed through a proxy, use POST with a JSON body because it avoids URL length limits when event properties are verbose and makes the request body easier to inspect in proxy logs. The proxy then constructs the GET or POST call to `trk.kissmetrics.io` however you prefer.

### Is Kissmetrics still a good choice for a new FlutterFlow app in 2026?

Kissmetrics is a legacy platform with declining market share and a history of ownership changes and service disruptions. If you are starting a new FlutterFlow project and choosing an analytics platform, Mixpanel and Amplitude are better choices — they offer equivalent or superior person-based analytics, modern Flutter SDK support, free tiers, and active development. This tutorial is best suited for teams that already have a Kissmetrics account with historical data they want their new FlutterFlow app to contribute to.

### How do I track users who use the app on both iOS and Android devices?

After a user signs in, fire the `/a` alias call using the same real user ID regardless of device, and update App State `kmPersonId` to that real ID. Since all devices use the same real user ID as `_p` after sign-in, Kissmetrics automatically merges all events from all devices into one person timeline. The challenge is the pre-sign-in anonymous ID — each device generates its own anonymous UUID, and only one of them gets aliased to the real user ID. Events from a second device before that device's first sign-in will appear as a separate person until the alias fires on that device too.

---

Source: https://www.rapidevelopers.com/flutterflow-integrations/kissmetrics
© RapidDev — https://www.rapidevelopers.com/flutterflow-integrations/kissmetrics
