Mobile analytics for apps and games
An app or game sends events from up to three places: the app on the device, the game server, and the backend that validates store purchases. Mobile analytics on Jitsu, the MIT-licensed event pipeline, takes events from all three. Apps send through Segment's open-source mobile libraries pointed at your Jitsu domain, engines and backends send JSON to the HTTP API, and functions filter and reshape events before a warehouse and your product tools receive them.
TL;DR
- iOS, Android and React Native apps send through Segment's open-source libraries. Jitsu has no mobile SDK of its own.
- Game engines and backends send JSON to the HTTP API. There is no Unity, Unreal or Godot SDK.
- Every Jitsu Cloud workspace includes a ClickHouse warehouse with a query console.
- Jitsu bills per active event: 200k a month on Free, $99 a month for 2M on Business.
- No mobile measurement partner is a live Jitsu destination.
Jitsu fits if:
- Your team answers retention and revenue questions in SQL. Every Jitsu Cloud workspace includes a ClickHouse warehouse.
- Purchase and economy events come from your backend and belong in the same table as app events.
- Events need filtering, sampling or reshaping in code before Mixpanel, Amplitude or Braze sees them.
- The app already uses Segment's tracking API, or is moving off Segment.
Events to track
| Event | Sent from | Why it matters |
|---|---|---|
Application Installed, Application Opened | app, automatic with lifecycle tracking on | Install day and return visits for D1, D7 and D30 retention |
identify | app | Links the install's anonymousId to your account ID |
onboarding_step_completed | app | The step where new users stop |
paywall_viewed | app | The denominator for paywall conversion |
Order Completed | backend | Validated purchases, keyed by the store's transaction ID |
subscription_renewed | backend | Renewals the app never sees |
level_start, level_end | game client or server | Where players fail and quit |
earn_virtual_currency, spend_virtual_currency | game server | Sources and sinks of the economy |
performance_sample | app | Frame rate by device model, sampled |
The full plan has 33 events with properties, types and PII handling: download the tracking plan CSV, no form.
How the pipeline is laid out
iOS and Android apps use Segment's Analytics-Swift and Analytics-Kotlin with apiHost and cdnHost set to your Jitsu domain; React Native apps point @segment/analytics-react-native at Jitsu's /v1/batch (iOS, Android, React Native). Game clients and the backend use the HTTP API, the backend with a server-to-server write key.
Each connection runs its own chain of functions: Braze gets only the few events its campaigns read, and the warehouse gets everything a filter does not drop. If the warehouse is down, events wait in Jitsu's queue and load when it comes back (event streaming). Live destinations here: ClickHouse, BigQuery, Snowflake, Redshift, Postgres, MySQL, Mixpanel, Amplitude, PostHog, Braze, Statsig, Amazon S3, Google Cloud Storage and Webhook.
What others in the industry do
These write-ups describe other companies' own pipelines and a public naming standard. None of these companies is a Jitsu customer:
- Roblox moved analytics events out of one
events_hourlytable into a table per event. Jitsu's default is oneeventstable; a function moves an event family to its own table withJITSU_TABLE_NAME. - MY.GAMES describes clients resending batches over poor mobile connections, and attributes whose type changed between releases.
- Discord kept each application event in its own Redshift table, so retention queries joined many tables.
- Google Analytics 4's recommended events name the common game events; the tracking plan reuses them.
Example implementation (illustrative): a subscription habit app
Illustrative example: not a Jitsu customer. A subscription habit-tracking app has iOS and Android clients and a backend that validates App Store and Google Play purchases.
Every connection first runs strip-and-trust from the tracking plan page, which drops purchases sent with a client write key and removes never_send fields. After that, ClickHouse gets every event, Mixpanel gets product events, and the Braze connection runs this function, which passes identify calls and the five events Braze campaigns read:
import { JitsuFunction } from "@jitsu/protocols/functions";
import { AnalyticsServerEvent } from "@jitsu/protocols/analytics";
export const config = {
slug: "braze-allowlist",
name: "Braze allowlist",
description: "Passes identify calls, and the track events Braze campaigns use when they carry a userId.",
};
// The track events Braze campaigns and segments read. Everything else stays out of Braze.
const BRAZE_EVENTS = new Set([
"onboarding_completed",
"paywall_viewed",
"Order Completed",
"subscription_started",
"subscription_canceled",
]);
const brazeAllowlist: JitsuFunction<AnalyticsServerEvent> = async event => {
if (event.type === "identify") {
return event;
}
// Track events reach Braze only from signed-in users, so every one carries a userId.
if (event.type === "track" && event.userId && typeof event.event === "string" && BRAZE_EVENTS.has(event.event)) {
return event;
}
return "drop";
};
export default brazeAllowlist;
This code is built and deployed with jitsu-cli; the function editor in the Jitsu UI takes JavaScript, which is what jitsu-cli build outputs.
The function passes a track event only when it carries a userId, so Braze receives events from signed-in users only. An onboarding_completed sent before sign-in still lands in ClickHouse and Mixpanel.
Dropping events on the Braze connection leaves the bill unchanged, because they still reach ClickHouse and an event counts once if it reaches any destination. An event goes unbilled only when no connection passes it and no function called fetch before the drop.
Use cases
Event and game tracking plan
The 33-event plan, Segment's mobile setup, the HTTP API for engines, and backend purchases keyed by the store's transaction ID.
Filtering noisy events
Heartbeats, frame ticks, QA accounts and resent batches handled in a function, and the events never to sample.
Retention and revenue in ClickHouse
D1, D7 and D30 retention, sessions and first-week purchase revenue, in ClickHouse SQL against the default events table.
Where Jitsu does not fit
- Install attribution. No mobile measurement partner is a live destination, and Jitsu does not attribute installs to ad campaigns. Keep your attribution SDK.
- Engine SDKs. There is no Unity, Unreal or Godot SDK. Batching, retries and an offline queue in a game client are code your team owns.
- Event-heavy pricing. Jitsu bills per active event, so cost grows with events per user. Tools that bill per tracked user grow with users instead. Check your own volume against the Segment comparison.
- Cross-device identity below Enterprise. Identity stitching rewrites a user's earlier anonymous events in the warehouse, up to 30 days back, in six warehouses only (ClickHouse, BigQuery, PostgreSQL, Redshift, Snowflake, MySQL). It is part of Jitsu Cloud Enterprise and of self-hosted Jitsu. Without it, join on identify calls in SQL.
- Aggregation in the pipeline. Functions act on one event at a time. Rolling counts across a time window belong on the device or in the warehouse.
- Charts and schema validation. Jitsu does not do analytics and has no schema to author. Funnels live in Mixpanel, Amplitude, PostHog or SQL, and checking events against a plan is a function you write. See Jitsu vs PostHog and Jitsu vs Snowplow.
- Self-hosting without Kubernetes. Self-hosted Jitsu runs functions only on Kubernetes with the Jitsu operator. Jitsu Cloud is hosted in the United States (privacy policy); Jitsu's security page covers SOC 2 and encryption on Cloud.
What it costs
Jitsu bills on active events: an event successfully sent to at least one destination, counted once however many it reaches. Captured events are unlimited.
The Free plan includes 200k active events a month. Business is $99 a month for 2M, then $40 per additional 1M. Enterprise is custom (pricing).
To estimate volume, multiply monthly active users by sessions per user by events per session. The inputs below are hypothetical.
| Hypothetical inputs | Events a month | Active events | Business plan |
|---|---|---|---|
| 20,000 users × 10 sessions × 10 events | 2M | 2M | $99 |
| 50,000 users × 20 sessions × 15 events | 15M | 15M | $99 + 13 × $40 = $619 |
| 100,000 users × 20 sessions × 15 events, 12M of them heartbeats that a function removes on every connection, with no fetch call | 30M captured | 18M | $99 + 16 × $40 = $739 |
Dropped events are not billed unless the function called fetch before dropping them. A function that splits one event into several is billed per resulting event.
Questions people ask
Does Jitsu have an iOS or Android SDK? No. iOS and Android apps use Segment's open-source Analytics-Swift and Analytics-Kotlin libraries with apiHost and cdnHost set to your Jitsu domain, and React Native apps use @segment/analytics-react-native pointed at Jitsu's /v1/batch endpoint.
How do Unity or Unreal games send events to Jitsu? Game clients and servers send JSON to Jitsu's HTTP API: /api/s/track for one event, /v1/batch for a batch in Segment's format. Jitsu has no Unity or Unreal SDK.
Where should purchase events come from? From the backend, after it validates the purchase with the App Store or Google Play, sent over the HTTP API with a server-to-server write key and the store's transaction ID as order_id.
Does dropping noisy events lower the bill? Only for events that reach no destination at all. Dropped events are not billed unless the function called fetch before dropping them, and an event that reaches at least one destination counts once as an active event.
Get started with Jitsu
Get started on Jitsu Cloud. The Free plan includes 200k active events a month and a ClickHouse warehouse with a query console.
Download the tracking plan, no form. For volume, Enterprise features or self-hosting, book a demo.