Facebook events not showing in Events Manager (Flutter)
Last updated August 6, 2026
Check the delay first
Before you change any code, rule out the reporting pipeline. Meta's aggregate reporting in Events Manager is not real time. An event your app sent correctly can be absent from the view you are looking at simply because it has not been processed into that view yet.
So do not debug against the aggregate dashboard. Use Test Events in Events Manager instead: open your app in Events Manager, go to the Test Events tab, then trigger the event by hand on a device. Test Events shows events within seconds, which turns the question of whether an event arrived into a yes or a no.
Two outcomes, and they send you to different halves of this page. If the event appears in Test Events, delivery works and your problem is attribution: skip to the last section. If nothing appears after a hand-triggered event, the event is not reaching Meta, and the configuration sections below are where to start.
One detail while you are testing. The SDK stores events and sends them in batches, so call flush() after the event you are testing: it pushes anything stored to the server immediately, which removes one more reason for an event to be late.
Debug in this order
Three layers, in this order. Each one can produce the symptom on its own, and each is cheaper to rule out than the one after it.
- Configuration. App id, client token, and the manifest or plist entries that point the SDK at them. If these are wrong, nothing is ever sent.
- Transport. Graph API version, event parameter value types, and the settings that suppress sending. Events are created in your code and never accepted by Meta.
- Attribution. Events arrive and are recorded, but the numbers attached to your campaigns disagree with your own data.
The order matters because attribution problems look exactly like delivery problems from the outside. Both present as a count that is too low, or zero. Most people start debugging in the layer they wrote themselves, which is usually the layer where nothing is broken, and lose a day there. Establish that events arrive before you argue about what the numbers mean.
Android configuration
Two things have to be in place. Having one without the other is the most common Android cause of nothing arriving.
The string resources
In android/app/src/main/res/values/strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="facebook_app_id">[APP_ID]</string>
<string name="facebook_client_token">[CLIENT_TOKEN]</string>
<string name="fb_login_protocol_scheme">fb[APP_ID]</string>
<string name="app_name">[APP_NAME]</string>
</resources>The manifest references
The string resources alone are not enough. The meta-data entries in AndroidManifest.xml are what the SDK actually reads at startup. Without them the values sit in your resources and nothing ever looks them up.
<application android:label="@string/app_name" ...>
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
<meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/>
</application>Build flavors
If your app has build flavors, check which strings.xml you edited. A flavor's resource directory overrides the main one, so values placed in the wrong flavor's strings.xml are simply not present in the build you are running. This is a frequent cause and it hides well: the file you have open on screen looks correct.
Build the flavor you are testing and check the merged manifest and merged resources that the build produces, not the source files you edited.
iOS configuration
All three keys belong in Info.plist:
<key>FacebookAppID</key>
<string>[APP_ID]</string>
<key>FacebookClientToken</key>
<string>[CLIENT_TOKEN]</string>
<key>FacebookDisplayName</key>
<string>[APP_NAME]</string>A missing or wrong FacebookClientToken is one of the most common causes of events silently not arriving. The app builds. The SDK initializes. Your calls to logEvent return without error. Nothing reaches Events Manager, and nothing in your app tells you why.
Get the value from the App Dashboard under Settings > Advanced > Security > Client token, then compare it character by character against what is in Info.plist. A client token copied from a different app in the same business account looks entirely plausible and will not work.
The Graph API version Meta removed
Facebook SDK v18.x ships with a default Graph API version that Meta has already removed from production. The default is different on each platform.
| Platform | SDK default | Removed by Meta |
|---|---|---|
| iOS SDK v18.x | v17.0 | 12 September 2025 |
| Android SDK v18.x | v16.0 | 14 May 2025 |
Why pinning a version matters
A removed version is not a cliff. Meta's versioning guide states that once a version is no longer usable, calls made to it are set to default to the oldest next version that is still usable. So the requests are still served, just by whatever version Meta routes them to rather than the one your app asked for. If you pinned a version deliberately, that is exactly the situation you pinned it to avoid.
What actually lands on you is the notice. An app on a stale default gets a deprecation email from Meta with a removal deadline, and that deadline comes from Meta's current developer notification floor, not from the original expiry date of the version you happen to be on. One of these was reported on this plugin as issue #474:
Your app is currently accessing a version of the Marketing API prior to v23.0. On February 19, 2026, all versions prior to v23.0 will be removed.
The floor moves on Meta's schedule, so the version and the date in the notice you get will not be those. The shape is the point: a deadline you did not choose, on a version you did not knowingly pick.
What the plugin does about it
facebook_app_events overrides the Graph API version during plugin initialization, so most apps need no configuration for it at all. As of plugin 0.30.3 the version it pins is v24.0. Treat the plugin's README and CHANGELOG as the source of truth for the current value, because it moves as Meta's supported range moves.
If you need a specific version, for example to match your backend, call setGraphApiVersion as early as possible in startup, before anything that can trigger a Graph API request. Your call wins: the plugin sets its default when it attaches, and your Dart call runs after that.
final facebookAppEvents = FacebookAppEvents();
// Optional. The plugin already sets a default at initialization.
await facebookAppEvents.setGraphApiVersion('v24.0');
await facebookAppEvents.activateApp();Two cases are left on the SDK default. An app that uses the native SDK directly, without this plugin in the initialization path, gets the version the SDK ships rather than a current one. So does a fork that removed the override.
Meta has not fixed it. When SDK v19 ships with a corrected default, the override becomes a no-op and the call above can be removed from your code.
Parameter values the SDK silently drops
The native Facebook SDKs accept only String and numeric event parameter values. An event carrying a value of any other type is dropped by the SDK: silently, with no error, and nowhere in Events Manager. Not just the offending parameter. The whole event.
facebook_app_events turns that silence into something you can see. logEvent accepts String, num and bool. Booleans are converted to "1" and "0", following Meta's yes and no convention, so the event is recorded identically on both platforms. Any other non-null type throws an ArgumentError at the call site instead of disappearing.
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)},
);This section is here because a silently dropped event is exactly the symptom that brings people to this page. If you call the native SDK directly anywhere in your app, or you log events through another wrapper, check the value types there. An ArgumentError from this plugin is good news by comparison: it names the parameter that is wrong.
ATT and consent on iOS
This plugin does not implement the ATT prompt, does not manage consent, and does not make your app compliant. That is your app's responsibility, and no plugin can take it over for you.
What the plugin does do is expose the native SDK's own privacy toggles. Setting those correctly is also your app's job, and getting one of them wrong produces missing data with no error attached to it.
setAdvertiserIdCollectionEnabled(bool)
Maps 1:1 to the native setting on both platforms: Settings.shared.isAdvertiserIDCollectionEnabled on iOS and FacebookSdk.setAdvertiserIDCollectionEnabled on Android. It controls whether the advertiser id, the IDFA on iOS or the Google Advertising ID on Android, is sent with your events. On iOS the advertiser id is only available once ATT authorization has been granted, so setting this to true does not by itself produce an identifier.
setAdvertiserTracking is deprecated and does nothing on iOS 17+
If your app still calls it and expects an effect, you have a silent bug. Settings.isAdvertiserTrackingEnabled was deprecated in Facebook SDK v17. The SDK now derives tracking consent from ATTrackingManager.trackingAuthorizationStatus and ignores the setter on iOS 17+. On Android no tracking-enabled flag exists at all, so the call reduces to setAdvertiserIdCollectionEnabled(enabled && collectId). Use setAdvertiserIdCollectionEnabled instead, and request ATT authorization in your app.
Two more paths that suppress data
setDataProcessingOptions and setLimitEventAndDataUsage both restrict what Meta is allowed to do with what you send: Limited Data Use in the first case, and in the second, any use beyond analytics and conversions. Either one, set somewhere in startup, can explain reporting you consider missing. Search for both, including inside a consent SDK you did not write yourself.
What this does to your numbers
If the ATT prompt has not been answered, or your consent gating suppresses initialization, events do not flow. The gap in Events Manager is identical to the gap a broken integration produces. That is why this section sits between configuration and attribution: it is the layer where the app is correct, the plugin is correct, and the data is still not there.
When it is attribution, not delivery
If Test Events shows your event, the configuration above checks out, and the campaign numbers still disagree with your own database, you do not have a delivery problem. You have an attribution problem, and it is a different investigation with different tools.
The usual causes:
- SKAdNetwork conversion windows and value mapping. For SKAdNetwork attribution on iOS, what Meta receives is a postback on Apple's schedule carrying the conversion value you configured, not the event as you logged it. If that mapping does not represent what you want the campaign to learn from, the campaign learns from the wrong signal, and the totals will not line up with your database row by row.
- Conversions API server events overlapping client events. When the same purchase is sent from the app and from your server without a shared deduplication key, Meta has nothing reliable to match them on and may count it twice.
- Attribution windows. Meta credits a conversion to the click or view that preceded it inside its window. Your database credits it to whatever your own model says. Two models over the same events give two different numbers, and neither of them is a bug.
All three are checkable. None of them is checkable from a web page. They need the build you actually ship, the Events Manager account, the ad account and your own numbers next to each other, because the answer is usually in the disagreement between them rather than in any one of them.
That is the honest limit of a written guide. If you have worked through everything above, your events arrive, and the money still does not add up, what is left is someone reading your setup with the data in front of them. The options below say which of those cases we handle for free and which one we charge for.
Verify your setup
- Test Events in Events Manager shows the event when you trigger it by hand
- Android: facebook_app_id and facebook_client_token are set in the strings.xml of the flavor you are actually building
- Android: both com.facebook.sdk.ApplicationId and com.facebook.sdk.ClientToken meta-data entries are in AndroidManifest.xml
- iOS: FacebookAppID, FacebookClientToken and FacebookDisplayName are all in Info.plist
- Every event parameter value is a String or a number, with structured values encoded as JSON
- activateApp is called on startup
- On iOS, the ATT prompt has been answered and consent gating is not suppressing initialization
- The app id you are debugging matches the app you have open in Events Manager
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