What Facebook App Events covers in Flutter, and what it does not
Last updated August 7, 2026
What App Events is
App Events is how Meta learns what happens inside your app. Your app logs a named event, the Facebook SDK batches it and sends it, and it appears in Events Manager. The same events are what Meta's ad reporting attributes to your campaigns.
Meta's own App Events overview is a short index rather than a reference. It describes App Events as letting your app "track events, such as a person installing your app or completing a purchase", then links onward to the per-platform guides. If you arrived from that page looking for the method list, the next section is the shortcut.
facebook_app_events covers that surface and only that surface. Facebook Login and sharing are separate SDK components and are not part of this plugin.
The API maps 1:1 to the native SDKs
This is the most useful thing to know about the plugin, and what it means in practice is that you read Meta's documentation rather than ours.
The plugin mirrors the App Events surface of the native SDKs 1:1. If a method exists on AppEvents on iOS, or on AppEventsLogger, or among the related Settings and FacebookSdk toggles on Android, you should find it here under the same name. A method name from Meta's native reference is the name to call from Dart.
Meta's Android reference for AppEventsLogger is live and directly usable. logEvent, logPurchase, logPushNotificationOpen, logProductItem, flush and getApplicationId are all documented there, with the signatures and the notes you want.
Its iOS counterpart is less dependable. The FBSDKCoreKit reference URLs that this plugin's own doc comments point at returned Page Not Found when this page was last checked, and Meta's iOS reference index listed no AppEvents entry at all. Until that settles, read the AppEvents declaration in FBSDKCoreKit itself.
Where the platforms genuinely differ, the plugin says so rather than papering over it. clearUserDataForType works on iOS and is a no-op on Android, which logs a warning: use clearUserData() there.
What the plugin does not expose
Four groups of native API are left out on purpose, because they do not translate to Flutter:
- The access-token overloads of
logEventandlogPurchase. - Hybrid webview augmentation:
augmentWebViewandaugmentHybridWebView. - The Unity integration hooks.
- iOS-only
logFailedStoreKit2Purchase.
So if you cannot find one of those, it is absent by decision and not by oversight. The decision is reversible: open an issue on the repository and make the case for your use.
Parameter values: the rule that drops whole events
Read this section even if you skip the rest.
The native Facebook SDKs accept only String and numeric event parameter values. An event carrying a value of any other type is dropped: silently, with no error, and nowhere in Events Manager. Not the offending parameter. The whole event.
facebook_app_events makes that failure visible instead:
| Value | What the plugin does |
|---|---|
String | Passed through unchanged |
num | Passed through unchanged |
bool | Converted to "1" or "0", following Meta's yes and no convention, so both platforms record the event identically |
null | The key is dropped. No error. The rest of the event is sent |
| Anything else | Throws ArgumentError, naming the offending key |
The null row is the one to pause on, because it is the one that does not throw. An optional value that happens to be absent quietly leaves its parameter out of an event that otherwise arrives intact. Usually that is what you want. It is not what you want when that parameter is the one you report on.
Structured values have to be encoded as a JSON string first, which is what Meta prescribes for parameters such as fb_content:
// Throws ArgumentError: a List is not an accepted parameter value type.
await facebookAppEvents.logEvent(
name: 'checkout_started',
parameters: {'fb_content': items},
);
// Correct: encode the structure as a JSON string first.
await facebookAppEvents.logEvent(
name: 'checkout_started',
parameters: {'fb_content': jsonEncode(items)},
);The rule applies wherever the plugin normalizes parameters, which is logEvent, logPurchase and logProductItem. Anywhere you call the native SDK directly, or log through another wrapper, you get the native behavior instead: silence.
Starting up, and when events actually send
activateApp() logs activation and install events. You need it only if automatic app event logging is disabled or delayed, which is the usual shape when consent gates initialization. If FacebookAutoLogAppEventsEnabled on iOS or com.facebook.sdk.AutoLogAppEventsEnabled on Android is set to false, call it yourself.
You can pass an applicationId to log to an app id other than the one in your platform configuration. That override applies per call: the next activateApp() without one goes back to the default.
Events do not leave the device as you log them. The SDK stores them and sends them in batches. Two APIs decide when:
flush()sends anything stored immediately. It is what you want while testing, so an event you just triggered reaches Test Events in seconds instead of whenever the next batch goes.setFlushBehavior(FlushBehavior)chooses when batches go on their own.FlushBehavior.autois the SDK default: events are flushed periodically and when the app is backgrounded.FlushBehavior.explicitOnlystops automatic flushing, so nothing is sent until you callflush().
explicitOnly is worth knowing mainly as a cause. An app that sets it and then never calls flush() logs events that never leave the device, and the result in Events Manager is indistinguishable from an app that logs nothing at all. getFlushBehavior() reads the current value back, which is the quick way to find out what a codebase you inherited is doing.
Privacy is your app's job, not the plugin's
The plugin does not implement the ATT prompt, does not manage consent, and does not make your app compliant. No wrapper can. That work belongs to your app.
It does expose the SDK's own privacy toggles, and setting those correctly is also your app's job. Both halves are true, and neither one replaces the other. The plugin hands you the switches. Getting one wrong produces missing data with no error attached to it.
Which switch does what, and why setAdvertiserTracking is deprecated and does nothing on iOS 17 and above, is covered in Facebook events not showing in Events Manager.
Verify your setup
- Every event parameter value is a String, a number or a bool, with structured values encoded as a JSON string
- You know which parameters can be null, because a null value is dropped without an error
- The native method you looked up in Meta's documentation exists on FacebookAppEvents under the same name
- You are not relying on augmentWebView, the Unity hooks, the access-token overloads or logFailedStoreKit2Purchase, none of which the plugin exposes
- If automatic app event logging is disabled in your platform configuration, activateApp is called explicitly
- getFlushBehavior does not return explicitOnly, or if it does, flush is called somewhere in your code
- Your app requests ATT authorization itself, because the plugin does not
- You know which SDK privacy toggles your app sets, including any set by a consent SDK you did not write
Meta's reference documentation
Plugin API reference
Still stuck?
It is a plugin defect
If the plugin is doing something the native Facebook SDK does not, that is our bug. Open an issue and we fix it. Free, always, no conditions.
Open a GitHub issueIt is a usage question
Configuration and integration questions are best asked where other developers can find the answer later.
Ask on StackOverflowYour numbers are wrong and money is moving
If Meta install campaigns are spending and the attribution does not add up, that is a different problem from a broken build. One hour, 300 USD, credited against the audit if you go ahead.
See the diagnostic and audit