dartpub.dev DartNative · beta
plugins / posthog_kit
ph

posthog_kit

v0.1.0 MIT

PostHog analytics for DartNative with posthog_flutter's API, over PostHog's HTTP API.

PostHog product analytics for DartNative apps with posthog_flutter's API. It covers setup, capture, screen, identify, alias, group, register and unregister, reset, flush, opt-out and debug. Feature-flag getters are no-ops. Pure Dart over PostHog's HTTP API, with a persisted anonymous id, an offline queue that survives relaunch, batched gzipped sends with retry, and Application Opened / Backgrounded lifecycle events. iOS and Android. Setup: list dartnative_path_provider as a direct dependency of your app (a transitive plugin isn't built into the app yet), and declare INTERNET in the main Android manifest; minSdk 26 because of path_provider. API shape credited to posthog_flutter (MIT).

by AbdurahmanAlmehdi/posthog_kit · DartNative ≥ 3.0 · updated today
Install
Free
pubspec.yaml
dependencies:
  posthog_kit:
    hosted: https://dartpub.dev
    version: ^0.1.0
Weekly installs
0
Active apps
0
Rating
0.0 · 0
Open issues
0

posthog_kit

PostHog product analytics for DartNative apps, with posthog_flutter's Dart API. Code written for posthog_flutter ports by changing one import.

// import 'package:posthog_flutter/posthog_flutter.dart';
import 'package:posthog_kit/posthog_kit.dart';

posthog_flutter is a method-channel plugin, which DartNative can't load. posthog_kit is pure Dart over PostHog's HTTP ingestion API (/batch/):

  • an anonymous distinct id that persists across launches,
  • an offline queue kept on disk and sent in gzipped batches, with retry and exponential backoff,
  • Application Installed/Updated/Opened/Backgrounded from the app lifecycle,
  • identify, alias, group, super properties, opt-out and personProfiles, with the same semantics as PostHog's other SDKs.

Setup

dependencies:
  dartnative_path_provider: ^1.0.0   # required, see below
  posthog_kit:
    hosted: https://dartpub.dev
    version: ^0.1.0
dn pub get

posthog_kit keeps its queue in the app-support directory, through dartnative_path_provider. dn pub get builds that plugin into your app for you. On a DartNative SDK older than 70531222383, it didn't when the plugin came in only through another package (DartNative/dartnative#49): there, list dartnative_path_provider: ^1.0.0 in your app too. Without it, posthog_kit keeps events in memory for the session and logs [PostHog] app-support directory unavailable ….

Android needs minSdk 26, the default of apps created with a current dn create. An older app on 24 needs minSdk = 26 in android/app/build.gradle.kts.

Android also needs the INTERNET permission in android/app/src/main/AndroidManifest.xml. The DartNative template declares it only in the debug and profile manifests (DartNative/dartnative#50), so a release build without this line can't send anything:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET"/>

iOS needs nothing: no Info.plist keys (PostHog's hosts are HTTPS).

Usage

import 'package:dartnative/dartnative.dart';
import 'package:posthog_kit/posthog_kit.dart';

import 'dartnative_plugin_registrant.dart';

Future<void> main() async {
  DartNativePluginRegistrant.registerAll();
  final config = PostHogConfig('phc_your_project_token')
    ..host = 'https://eu.i.posthog.com'   // default: https://us.i.posthog.com
    ..appVersion = '1.4.0'                // enables Application Updated
    ..appBuild = '42'
    ..debug = true;
  await Posthog().setup(config);
  runApp(const HomeScreen());
}

Then anywhere:

await Posthog().capture(eventName: 'trip_created', properties: {'km': 120});
await Posthog().screen(screenName: '/trips');       // later events carry $screen_name
await Posthog().identify(userId: user.id, userProperties: {'role': 'owner'});
await Posthog().group(groupType: 'organization', groupKey: org.id);
await Posthog().register('environment', 'prod');    // super property
await Posthog().reset();                            // sign-out
await Posthog().flush();                            // send now
await Posthog().disable();                          // opt out (persisted)

A pure-Dart package can't read the app version from the bundle, so pass it in: PackageInfo.fromPlatform() from dartnative_system has it. Without appVersion, Application Installed and Application Opened still fire, but Application Updated can't be detected.

Calls made before setup completes, or after close, are ignored, as in posthog_flutter.

Screen views

DartNative's NavigatorObserver has no didPush, so there is no PosthogObserver. Call Posthog().screen(screenName: …) from your navigation helper where you push routes.

Additions for DartNative

These PostHogConfig fields have no upstream equivalent:

Field Purpose
appVersion, appBuild $app_version/$app_build, and install/update detection
osVersion $os_version. Parsed automatically on iOS (26.1). Android exposes no release number to pure Dart, so it is omitted there unless you pass it
httpClient an http.Client to send through (a proxy, a Dio wrapper, a test mock)
storage a PostHogStorage; default FilePostHogStorage under the app-support directory. InMemoryPostHogStorage keeps nothing on disk
libraryName the $lib value, default posthog-dartnative ($lib_version is always sent)
onLog receives debug lines instead of dnLog

Posthog().queueLength returns the number of events waiting. PostHogClient is public, so tests can build one with an InMemoryPostHogStorage and MockClient from package:http/testing.dart, and drive lifecycle with onForeground() and onBackground().

Delivery

  • Events are persisted before capture completes, then sent when 20 are queued (flushAt), every 30 s (flushInterval), when the app goes to the background, on flush(), and at the next setup.
  • 2xx removes a batch. 413 halves the batch; a single event that still gets 413 is dropped. 408, 429 and 5xx are retried 3 times, then the batch is dropped (429 honours Retry-After). Network errors are retried without a limit. Other 4xx drop the batch.
  • Retries back off exponentially (5 s doubling, capped at 5 min, full jitter). Past maxQueueSize (1000) the oldest event is dropped.
  • Each event carries a UUIDv7 uuid, so PostHog deduplicates a batch whose response was lost.
  • Application Opened fires on a resume only after a real background, not after inactive (a Face ID prompt or Control Center).
  • The flush on background is best-effort: pure Dart can't hold an iOS background task. Anything unsent is sent on the next launch.

Not supported

posthog_flutter API Here
Feature flags isFeatureEnabled → false; getFeatureFlag, getFeatureFlagPayload → null; reloadFeatureFlags is a no-op. The rest isn't provided
Session replay, surveys config flags accepted and ignored (debug warning); widgets not provided
Error tracking, logs, push notifications not provided
PosthogObserver, PostHogWidget not provided; see Screen views
Rage clicks, dataMode, autocapture not provided

Context properties are thinner than the native SDKs': $os, $os_version, $device_type, $locale, $timezone, $app_version, $app_build and $session_id, with no device model, screen size or network type.

Example

example/lib/main.dart has buttons for capture, screen, identify, group, reset and flush, and shows every debug line. With no key it sends to an unreachable local port, so events stay queued across relaunches:

cd example && dn pub get && dn run
dn run --dart-define=POSTHOG_API_KEY=phc_… # send to PostHog for real

Credits & license

The API mirrors posthog_flutter 5.48.0 by PostHog (MIT, Copyright (c) 2020 PostHog). The wire format and retry rules follow PostHog's @posthog/core (Apache-2.0), used as a reference only; no code was copied from either. This is an independent pure-Dart implementation. "PostHog" is a trademark of PostHog Inc.; this package isn't affiliated with or endorsed by it.

posthog_kit's code is MIT, see LICENSE. Full notices are in THIRD_PARTY_NOTICES.