▸Install the Flutter SDK
# pubspec.yaml
dependencies:
flutter:
sdk: flutter
respectlytics_flutter: ^3.0.0
Pure Dart — no platform channels for analytics. Same code on every platform Flutter compiles to (iOS, Android, web, macOS, Windows, Linux). On web, events are sent via the REST API; mobile platforms use the same path.
▸Initialize Respectlytics in Flutter
import 'package:flutter/material.dart';
import 'package:respectlytics_flutter/respectlytics_flutter.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Respectlytics.configure(appKey: '<YOUR_APP_KEY>');
runApp(const MyApp());
}
Initialize in main() after WidgetsFlutterBinding.ensureInitialized() and before runApp(). The future completes immediately on configuration; events queued before completion are flushed once the network is available.
✦Privacy & implementation notes
GDPR's Article 4(1) classifies IP addresses as personal data, with narrowing case law on transient-purpose processing. The ECJ's Patrick Breyer v. Bundesrepublik Deutschland (2016) and subsequent cases established that even "dynamic" IPs are personal data when the recipient has the means to identify the user. The transient-discard pattern minimises the data-retention surface but doesn't eliminate the legal classification — consult your legal team.
The country code stored in events is sufficient for the most common product breakdown — "how does this metric vary by market?". Going deeper (city, ZIP) almost always falls into either a marketing-ads use case (handled elsewhere) or a vanity dashboard that doesn't drive product decisions.
The Flutter SDK is pure Dart. No MethodChannel, no platform-specific iOS or Android plugin code. The same code runs on every platform Flutter supports — including web and desktop targets. This eliminates one common audit surface ("what's the Android implementation doing?").
Always initialize after WidgetsFlutterBinding.ensureInitialized() and before runApp(). If you skip the binding step, the configure call will throw on platforms that need a binding for asynchronous I/O. The SDK documentation example uses this pattern by default.
⇋How this compares to other analytics SDKs
| Geolocation handling | Firebase Analytics | Mixpanel | Amplitude | Respectlytics |
|---|---|---|---|---|
| Stores IP address | Yes | Yes (90 days default) | Yes | No (discarded after lookup) |
| Stores precise lat/long | Optional | Optional | Optional | No |
| Stores city / region | Yes | Yes | Yes | No |
| Stores country code | Yes | Yes | Yes | Yes |
| Per-user location history | Yes | Yes | Yes | No |
| Reverse-DNS or VPN detection | Yes | Yes | Yes | No |
❓Frequently asked questions
Is the IP-address-then-discarded path still considered processing PII?
Most regulators (including the EU's EDPB) classify IP addresses as personal data even when transiently held for a strictly defined purpose. The transient-then-discarded pattern is generally accepted as the most minimised viable approach for country lookup. Consult your legal team for the exact framing in your jurisdiction; the standard disclaimer applies.
How accurate is the country lookup?
We use MaxMind GeoLite2's country database, refreshed monthly. Accuracy is ~99% for standard residential and mobile IP ranges; lower for VPNs, Tor, and corporate egresses. For country-level rollups in product analytics, the accuracy is sufficient.
Can we get city-level breakdowns for marketing?
Not from Respectlytics, by design. City-level geolocation is one of the more privacy-sensitive analytics fields and is not aligned with the ROA philosophy. If you genuinely need city-level breakdowns for paid ads campaigns, your ads platform provides them on its own (Google Ads, Meta Ads) — that lives in the ads attribution layer, not in product analytics.
What about regions like Hong Kong / Taiwan / Crimea — how are they assigned?
Respectlytics uses ISO 3166-1 alpha-2 country codes from MaxMind. Regions with politically contested status are coded by MaxMind's geographic convention, not by political alignment. If your audience needs a finer regional breakdown for a specific reason, the workaround is to fire distinct event_names per region of interest.