b2metric_sdk 1.1.0
b2metric_sdk: ^1.1.0 copied to clipboard
B2Metric analytics SDK for Flutter. Collects events, manages sessions, and supports push notifications on Android and iOS.
b2metric_sdk #
B2Metric analytics SDK for Flutter. Collects events, manages sessions, and supports push notifications on both Android and iOS.
Features #
- Custom event tracking with properties and item-level data
- A/B testing with stored experiment assignments, exposed as a listenable and a stream
- User identification with custom attributes (
setUser) - Automatic session management (
first_open,session_start,session_end) - Push notification token registration (FCM, HMS, APNS) and open tracking
- Offline event queuing with persistent storage
- Automatic batching, retry with exponential backoff, and network-aware delivery
- Automatic device and app metadata collection
- Configurable log levels for debugging
- Zero third-party dependencies (uses Flutter SDK only)
Requirements #
- Flutter >= 3.10
- iOS 13+ / Android API 24+
Installation #
dependencies:
b2metric_sdk: ^1.1.0
Quick Start #
import 'package:b2metric_sdk/b2metric_sdk.dart';
// Initialize at app startup
await B2Metric.instance.init(
const B2MetricConfig(
apiKey: 'YOUR_API_KEY',
appIdentifier: 'YOUR_APP_IDENTIFIER',
),
);
// Track an event
B2Metric.instance.logEvent('button_click', properties: {
'screen': 'home',
});
Initialization #
Call init() once at app startup before using any other SDK method. Subsequent calls are ignored.
await B2Metric.instance.init(
const B2MetricConfig(
apiKey: 'YOUR_API_KEY',
appIdentifier: 'YOUR_APP_IDENTIFIER',
logLevel: LogLevel.debug,
),
);
Configuration Options #
| Option | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
apiKey |
String |
Yes | — | — | Your B2Metric API key |
appIdentifier |
String |
Yes | — | — | Identifier of your app registered in B2Metric (see format rules below) |
baseUrl |
String |
No | "https://tracker.b2metric.com" |
— | API endpoint URL |
batchSize |
int |
No | 20 |
1–100 | Events per batch before sending |
flushIntervalSeconds |
int |
No | 30 |
1–3600 | Seconds between automatic flushes |
maxRetries |
int |
No | 3 |
1–10 | Retry attempts for failed requests |
sessionTimeoutMinutes |
int |
No | 30 |
1–10080 | Inactivity before a new session starts |
maxQueueSize |
int |
No | 1000 |
100–10000 | Max events held in queue |
experimentIds |
List<String> |
No | [] |
— | Experiments this app takes part in (see A/B Testing) |
experimentsBaseUrl |
String |
No | https://experiments-api.b2metric.com |
— | Experiments endpoint; override only for test/staging |
logLevel |
LogLevel |
No | LogLevel.off |
off · error · warning · info · debug |
Console log verbosity |
Values outside the allowed range are clamped automatically.
appIdentifier format
appIdentifier must be lowercase snake_case:
- Allowed characters:
a–z,0–9and_ - Must start with a letter
- Cannot contain spaces, hyphens, uppercase letters, Turkish or other non-ASCII characters, or consecutive
__ - Cannot start or end with
_
| ✅ Valid | ❌ Invalid |
|---|---|
my_app |
MyApp (uppercase) |
my_app_v2 |
my-app (hyphen) |
checkout_web |
my app (space) |
app123 |
şirket (Turkish character) |
a_b_c |
123app (leading digit) |
_myapp / myapp_ (leading/trailing _) |
|
my__app (consecutive _) |
Event Tracking #
Basic Event #
B2Metric.instance.logEvent('page_view', properties: {'page': 'home'});
Event with Item Properties #
B2Metric.instance.logEvent(
'add_to_cart',
properties: {'total': 3000, 'currency': 'USD'},
itemProperties: [
{'id': 'SKU-123', 'name': 'Running Shoes', 'price': 2850, 'quantity': 1},
{'id': 'SKU-456', 'name': 'Socks', 'price': 150, 'quantity': 2},
],
);
Supported Property Types #
String, num, bool, DateTime, null, Map<String, dynamic>, and List<dynamic>. Unsupported values are dropped with a warning.
User Identification #
Call setUser to associate events with a known user. The userId is your own application's user identifier — the SDK does not generate or validate it. Call it once the user is known (typically at session start, e.g. after login) and again whenever the user's details change.
B2Metric.instance.setUser(B2MetricUser(
userId: 'user_123',
name: 'Ahmet',
email: 'ahmet@example.com',
properties: {'plan': 'premium'}, // any custom attributes
));
userId is required; name, surname, and email are suggested fields. Custom attributes are passed via properties.
setUser does two things:
- Sends a
user_identifyevent that creates or updates the user's profile attributes. - Merges the attributes into the
user_propertiesof every subsequent event, so they are available for event-level analysis.
Device fields cannot be overridden. If a custom attribute uses the same key as a collected device property (e.g.
device_id,os_version), the device value always wins.
The user_properties attached to each event is a snapshot taken at the moment the event is tracked. Calling setUser later does not change already-queued events. User attributes are not persisted across restarts, so call setUser again after each app launch.
Push Notifications #
Register Token #
B2Metric.instance.registerPushToken(token, PushProvider.fcm);
Supported providers: PushProvider.fcm, PushProvider.hms, PushProvider.apns.
Track Push Opened #
B2Metric.instance.trackPushOpened({
'campaign_id': 'summer_sale',
'deep_link': 'app://offers/42',
});
A/B Testing #
Show different variants to different devices and let B2Metric decide who sees what. Experiments are created in your B2Metric panel; your app reads the assignment and renders accordingly.
Assignments are fetched when the SDK starts, stored on the device, and read synchronously — there is no loading state to thread through your widget tree.
List the experiments your app takes part in:
await B2Metric.instance.init(
B2MetricConfig(
apiKey: 'YOUR_API_KEY',
appIdentifier: 'my_app',
experimentIds: ['YOUR_EXPERIMENT_ID'],
),
);
Rebuild when assignments change:
ValueListenableBuilder<ExperimentsSnapshot>(
valueListenable: B2Metric.instance.experiments,
builder: (context, snapshot, _) {
final groupId = snapshot.assignments
.where((a) => a.experimentId == 'YOUR_EXPERIMENT_ID')
.map((a) => a.groupId)
.firstOrNull;
return groupId == 'YOUR_GROUP_ID'
? const BuyNowButton()
: const ContinueButton();
},
)
The same updates are also a broadcast stream, so Riverpod, Bloc, or your own controller can consume them instead:
B2Metric.instance.experimentChanges.listen((snapshot) { /* ... */ });
Outside the widget tree, read the value directly — it returns immediately:
final groupId = B2Metric.instance.getExperimentGroupId('YOUR_EXPERIMENT_ID');
Every experiment needs a default. The SDK never blocks rendering — when it
has no answer it returns null, whether the device is outside the experiment's
audience, the experiment has ended, or the first answer has not arrived yet.
Keep every identifier in one file that resolves null to a default, so no call
site can forget it.
📖 Full A/B testing guide → — choosing a listening shape, finding your group identifiers, verifying the integration, offline and first-launch behaviour, identified users, cleaning up a finished experiment, and troubleshooting.
Manual Flush #
B2Metric.instance.logEvent('purchase_completed', properties: {'order_id': 'ord_789'});
await B2Metric.instance.flush();
Shutdown #
await B2Metric.instance.destroy();
License #
MIT