Skip to content

ADX

Flutter Ads Integration in 2026: AdMob, Rewarded Ads, Mediation and Monetization Architecture

A detailed 2026 guide to adding ads to a Flutter app using Google Mobile Ads, rewarded and interstitial formats, mediation, consent, app-ads.txt and a maintainable monetization architecture.

On this page

If you are searching for "Flutter ads integration", "Flutter monetization SDK", "ads in Flutter app" or "Flutter AdMob integration", the implementation itself is only half of the problem.

The easy version is:

install plugin
→ initialize SDK
→ load ad
→ show ad

The production version is:

choose the right ad format
→ design a placement that does not damage retention
→ initialize the SDK correctly
→ handle lifecycle and disposal
→ use test inventory
→ collect consent where required
→ verify app-ads.txt and app readiness
→ keep provider code behind an abstraction
→ measure paid impressions
→ add mediation only when the data justifies it

That difference matters.

A Flutter app can technically show an ad and still have a poor monetization architecture, invalid-traffic risk, duplicated SDK logic, broken lifecycle handling or an ad experience that causes users to uninstall.

This guide covers the full implementation path for Flutter developers in 2026.

Current Flutter mobile-ad SDK landscape

As of 20 September 2026, the major Flutter monetization packages relevant to this guide include:

SDKCurrent package version checkedMain role
Google Mobile Ads9.1.0AdMob / Google Ad Manager ads and mediation
AppLovin MAX4.6.4MAX mediation and AppLovin demand
Unity LevelPlay9.2.0LevelPlay mediation
Theaimart ADX1.0.0Theaimart advertising SDK across Flutter platforms

The current Google package supports Android and iOS and exposes banner, interstitial, native and rewarded formats. Google's Flutter documentation also covers rewarded interstitial and app-open ads.

AppLovin's Flutter plugin supports Android and iOS with interstitial, rewarded, banner and MREC formats.

Unity's current Flutter mediation package is named unity_levelplay_mediation. The previous ironsource_mediation package is deprecated.

Theaimart's Flutter SDK is cross-platform and currently documents Android, iOS, web, Windows, macOS and Linux support.

Those products are not identical.

Google Mobile Ads can be used as both direct demand and a mediation control layer. MAX and LevelPlay are mediation platforms with their own demand relationships. ADX is a separate advertising route.

Before writing code: choose the monetization architecture

There are three reasonable starting architectures.

Architecture A: one provider

Flutter app
    ↓
Google Mobile Ads
    ↓
AdMob demand

This is the simplest architecture.

It is appropriate when:

  • you are launching monetization for the first time;
  • traffic is still small;
  • engineering simplicity matters;
  • you need a baseline before comparing networks.

Architecture B: mediation

Flutter app
    ↓
Mediation SDK
    ↓
multiple demand sources

Examples include AdMob mediation, AppLovin MAX and Unity LevelPlay.

This is useful when:

  • you have enough traffic to compare demand;
  • you want bidding or waterfall competition;
  • no-fill is meaningful;
  • you want to reduce dependence on one demand source.

Architecture C: provider abstraction

The application should ideally see this:

UI
 ↓
AdService
 ↓
provider or mediator

not this:

Screen A → Google SDK
Screen B → Google SDK
Screen C → AppLovin SDK
Screen D → custom callbacks

The abstraction is one of the most important engineering decisions in this article.

A production-safe Flutter ad service

Define what the application needs before choosing how a provider implements it.

For example:

ad_service.dart
abstract interface class AdService {
  Future<void> initialize();
 
  Future<bool> preloadInterstitial();
  Future<bool> showInterstitial();
 
  Future<bool> preloadRewarded();
  Future<bool> showRewarded({
    required Future<void> Function() onReward,
  });
 
  Future<void> dispose();
}

The UI now depends on an application-level contract.

It does not care whether the implementation uses:

  • Google Mobile Ads;
  • AppLovin MAX;
  • Unity LevelPlay;
  • Theaimart ADX;
  • a future provider.

This also makes a premium no-ads mode easier.

Your app can replace the production service with:

class NoAdsService implements AdService {
  @override
  Future<void> initialize() async {}
 
  @override
  Future<bool> preloadInterstitial() async => false;
 
  @override
  Future<bool> showInterstitial() async => false;
 
  @override
  Future<bool> preloadRewarded() async => false;
 
  @override
  Future<bool> showRewarded({
    required Future<void> Function() onReward,
  }) async => false;
 
  @override
  Future<void> dispose() async {}
}

Now monetization policy is separated from screen layout.

Part 1: Google AdMob in Flutter

Google's official Flutter package is google_mobile_ads.

The current pub.dev release checked for this guide is 9.1.0.

Google's changelog says 9.1.0 currently wraps:

  • Google Mobile Ads Android SDK 25.4.0;
  • Google Mobile Ads Next-Gen Android SDK 1.3.1;
  • Google Mobile Ads iOS SDK 13.7.0;
  • UMP Android SDK 4.0.0;
  • UMP iOS SDK 3.1.0.

That version detail will become stale, so treat it as a dated reference rather than a permanent requirement.

Install Google Mobile Ads

Run:

flutter pub add google_mobile_ads

Then import it:

import 'package:google_mobile_ads/google_mobile_ads.dart';

Google's current quick start requires the AdMob application ID to be configured at the native platform level.

For Android, the application ID belongs in AndroidManifest.xml.

For iOS, it is configured through Info.plist using GADApplicationIdentifier.

Use the application ID from the AdMob console.

Do not confuse the application ID with an ad unit ID.

They serve different purposes.

Initialize the SDK once

Google's documentation says to initialize the plugin before loading ads:

main.dart
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
 
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
 
  await MobileAds.instance.initialize();
 
  runApp(const MyApp());
}

A production app may initialize consent before requesting personalized advertising, which we cover later.

Should you await initialization?

For a simple single-network setup, awaiting initialization creates a clear startup sequence.

For mediation, initialization status matters more.

Google's current Flutter mediation guide explicitly says to wait for initialization before loading the first mediated ad so participating adapters have a chance to initialize.

Bidding adapters require explicit SDK initialization.

Never develop against live ad traffic

Google's guidance is direct: use test ads during development.

There are two main approaches:

  • Google's sample ad-unit IDs;
  • your own ad units with a test device configured.

Android emulators and iOS simulators are automatically treated as test devices.

Physical devices can be registered as test devices.

Mediated ads require additional care because third-party networks may need their own test mode.

Why this matters

Clicking or generating artificial activity on live inventory can be treated as invalid traffic.

Your test environment should make it impossible for normal development activity to create billable production behavior.

A simple configuration layer helps:

ad_ids.dart
import 'dart:io';
 
class AdIds {
  static const bool production = bool.fromEnvironment(
    'PRODUCTION_ADS',
    defaultValue: false,
  );
 
  static String get interstitial {
    if (!production) {
      return Platform.isAndroid
          ? 'GOOGLE_ANDROID_TEST_INTERSTITIAL_ID'
          : 'GOOGLE_IOS_TEST_INTERSTITIAL_ID';
    }
 
    return Platform.isAndroid
        ? 'YOUR_ANDROID_INTERSTITIAL_ID'
        : 'YOUR_IOS_INTERSTITIAL_ID';
  }
}

The exact Google sample IDs should be copied from the current official documentation.

The important design is that production inventory cannot accidentally become the development default.

Banner ads stay inside the widget layout.

Google currently recommends adaptive banner formats for responsive mobile layouts.

For a bottom anchored banner, the flow is:

  1. calculate the available width;
  2. request an adaptive AdSize;
  3. create BannerAd;
  4. listen for load/failure;
  5. render with AdWidget;
  6. dispose when the widget no longer needs the ad.

A simplified stateful widget can look like:

adaptive_banner.dart
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
 
class AdaptiveBanner extends StatefulWidget {
  const AdaptiveBanner({
    required this.adUnitId,
    super.key,
  });
 
  final String adUnitId;
 
  @override
  State<AdaptiveBanner> createState() => _AdaptiveBannerState();
}
 
class _AdaptiveBannerState extends State<AdaptiveBanner> {
  BannerAd? _ad;
 
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
 
    if (_ad == null) {
      _load();
    }
  }
 
  Future<void> _load() async {
    final width = MediaQuery.sizeOf(context).width.truncate();
 
    final size =
        await AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(
      width,
    );
 
    if (size == null || !mounted) return;
 
    final ad = BannerAd(
      adUnitId: widget.adUnitId,
      request: const AdRequest(),
      size: size,
      listener: BannerAdListener(
        onAdLoaded: (loadedAd) {
          if (!mounted) {
            loadedAd.dispose();
            return;
          }
 
          setState(() {
            _ad = loadedAd as BannerAd;
          });
        },
        onAdFailedToLoad: (failedAd, error) {
          failedAd.dispose();
        },
      ),
    );
 
    await ad.load();
  }
 
  @override
  void dispose() {
    _ad?.dispose();
    super.dispose();
  }
 
  @override
  Widget build(BuildContext context) {
    final ad = _ad;
    if (ad == null) return const SizedBox.shrink();
 
    return SafeArea(
      top: false,
      child: SizedBox(
        width: ad.size.width.toDouble(),
        height: ad.size.height.toDouble(),
        child: AdWidget(ad: ad),
      ),
    );
  }
}

The exact API available can change with package versions. Check the current Google docs when integrating.

Anchored vs inline adaptive banner

Google distinguishes two important responsive banner use cases.

Anchored adaptive banner

Best when the banner stays fixed at the top or bottom.

Inline adaptive banner

Designed for banners inside scrolling content.

Do not place a fixed-size banner into an arbitrary scrolling feed and assume it will behave well on every device.

Google also documents performance limitations for inline banners on older Android devices and recommends anchored banners when appropriate.

Interstitial ads

Interstitials are full-screen ads.

Google's current Flutter guidance says they should be used at natural transition points.

Good examples:

game level finished
→ interstitial
→ next level

or:

batch export finished
→ interstitial
→ results screen

Bad example:

user taps Save
→ ad unexpectedly blocks the save

The user should not feel that essential application controls are traps.

Load before you need the interstitial

Do not wait until the exact moment you want to show the ad and then begin network loading.

Preload it.

A simple service pattern:

google_interstitial_service.dart
import 'dart:async';
import 'package:google_mobile_ads/google_mobile_ads.dart';
 
class GoogleInterstitialService {
  GoogleInterstitialService(this.adUnitId);
 
  final String adUnitId;
  InterstitialAd? _ad;
  bool _loading = false;
 
  Future<bool> preload() async {
    if (_loading || _ad != null) return _ad != null;
 
    _loading = true;
 
    final completer = Completer<bool>();
 
    InterstitialAd.load(
      adUnitId: adUnitId,
      request: const AdRequest(),
      adLoadCallback: InterstitialAdLoadCallback(
        onAdLoaded: (ad) {
          _loading = false;
          _ad = ad;
          completer.complete(true);
        },
        onAdFailedToLoad: (error) {
          _loading = false;
          completer.complete(false);
        },
      ),
    );
 
    return completer.future;
  }
 
  Future<bool> show() async {
    final ad = _ad;
    if (ad == null) return false;
 
    _ad = null;
 
    ad.fullScreenContentCallback = FullScreenContentCallback(
      onAdDismissedFullScreenContent: (ad) {
        ad.dispose();
        preload();
      },
      onAdFailedToShowFullScreenContent: (ad, error) {
        ad.dispose();
        preload();
      },
    );
 
    ad.show();
    return true;
  }
 
  void dispose() {
    _ad?.dispose();
    _ad = null;
  }
}

You would import dart:async for Completer in this example.

The important pattern is:

preload
→ hold one eligible ad
→ show once
→ dispose
→ preload next

Google's documentation notes that an interstitial can only be shown once.

Do not attempt to reuse the same object.

Add product-level frequency caps

The ad SDK decides whether an ad can load.

Your application should decide whether an ad should be shown.

Example policy:

class InterstitialPolicy {
  InterstitialPolicy({
    required this.minimumGap,
  });
 
  final Duration minimumGap;
  DateTime? _lastShown;
 
  bool canShow(DateTime now) {
    final last = _lastShown;
    if (last == null) return true;
    return now.difference(last) >= minimumGap;
  }
 
  void markShown(DateTime now) {
    _lastShown = now;
  }
}

The duration should come from product testing, not from this example.

The key is to prevent SDK calls from becoming the monetization policy.

Rewarded ads

Rewarded ads are one of the most useful formats for games and some AI utilities.

The user chooses to interact with the ad in return for value.

Examples:

  • another game life;
  • more coins;
  • an extra export;
  • another AI generation;
  • temporary premium access.

Google's current Flutter API uses RewardedAd.load and the onUserEarnedReward callback when showing the ad.

A simplified service:

rewarded_service.dart
import 'dart:async';
import 'package:google_mobile_ads/google_mobile_ads.dart';
 
class RewardedService {
  RewardedService(this.adUnitId);
 
  final String adUnitId;
  RewardedAd? _ad;
 
  Future<bool> preload() {
    final completer = Completer<bool>();
 
    RewardedAd.load(
      adUnitId: adUnitId,
      request: const AdRequest(),
      rewardedAdLoadCallback: RewardedAdLoadCallback(
        onAdLoaded: (ad) {
          _ad = ad;
          completer.complete(true);
        },
        onAdFailedToLoad: (error) {
          completer.complete(false);
        },
      ),
    );
 
    return completer.future;
  }
 
  Future<bool> show({
    required Future<void> Function() onReward,
  }) async {
    final ad = _ad;
    if (ad == null) return false;
 
    _ad = null;
 
    ad.fullScreenContentCallback = FullScreenContentCallback(
      onAdDismissedFullScreenContent: (ad) {
        ad.dispose();
        preload();
      },
      onAdFailedToShowFullScreenContent: (ad, error) {
        ad.dispose();
        preload();
      },
    );
 
    ad.show(
      onUserEarnedReward: (ad, reward) async {
        await onReward();
      },
    );
 
    return true;
  }
 
  void dispose() {
    _ad?.dispose();
  }
}

Do not grant valuable rewards only from client trust

If the reward has real economic value, such as:

  • paid virtual currency;
  • expensive AI inference;
  • a financial entitlement;
  • inventory in a game economy;

consider server-side verification where the provider supports it.

Google's current Flutter rewarded documentation exposes server-side verification options.

A stronger flow is:

rewarded impression completed
→ ad platform verification callback
→ your backend validates
→ backend credits reward
→ app refreshes balance

That makes local tampering harder.

For a low-value cosmetic reward, client-side handling may be acceptable depending on your threat model.

Rewarded ads for AI applications

This format looks attractive:

watch ad
→ unlock one AI generation

But calculate the unit economics.

A simplified check is:

expected ad revenue per completed reward
>
expected variable cost of the unlocked AI action

If not, the ad is directly subsidizing compute.

The feature may still be valuable if it improves retention or later conversion, but measure that intentionally.

Do not assume "rewarded ad = free AI credit."

Native ads in Flutter

Native ads are different from banners.

Instead of receiving one pre-rendered rectangle, the app receives ad assets and is responsible for presenting them according to the platform's native-ad rules.

Google's Flutter documentation provides two paths:

  • predefined native templates;
  • custom platform-specific native layouts.

Custom native layouts require native Android/iOS code.

Google's current docs require a NativeAdFactory to be registered with a unique factory ID for custom platform rendering.

That is an important architectural cost.

If your product does not need a deeply integrated feed-style ad, a banner or another format can be much simpler to maintain.

When native ads make sense

Native ads are useful in:

  • content feeds;
  • article lists;
  • discovery surfaces;
  • card-based interfaces.

They are less useful when the app has no natural content unit to place them beside.

Do not disguise an ad as normal app content.

The advertisement needs to remain identifiable.

App-open ads

App-open ads are designed for the foreground/loading experience.

Google's current Flutter documentation says they can appear when a user opens or returns to the app.

This format can monetize frequent opens, but it also touches one of the most sensitive user-experience moments: startup.

Do not show one on every foreground event

Mobile applications enter and leave foreground for many reasons.

Examples:

  • notification shade;
  • external authentication;
  • file picker;
  • permission flow;
  • camera;
  • payment app;
  • browser;
  • phone call.

If every return causes an app-open ad, the product can become frustrating.

Create an eligibility policy.

For example:

show only when:
- app has been backgrounded for meaningful duration
- user is not in onboarding
- no critical flow is in progress
- frequency cap permits
- ad is already loaded

The exact policy depends on the app.

Rewarded interstitial ads

Rewarded interstitials are not identical to opt-in rewarded ads.

Google's current guidance says a rewarded interstitial appears automatically at a natural transition and requires an intro screen that explains the reward and lets the user opt out.

That makes product design especially important.

Use it only where the transition itself makes sense.

Do not surprise the user with an incentivized full-screen ad during a direct action.

Ad integration is not complete when the SDK loads successfully.

Advertising can involve device, consent and personalization signals that vary by user and jurisdiction.

Google's current EU consent guidance requires publishers serving relevant users in the EEA and UK to use a Google-certified CMP integrated with the IAB Transparency and Consent Framework for the required consent flow.

Google's User Messaging Platform is one supported route.

The important engineering principle is:

determine consent state
→ configure advertising behavior
→ initialize/request ads appropriately

not:

load personalized ads
→ ask consent afterward

India-based developer does not mean India-only privacy

Your company can be in India while users are:

  • in the UK;
  • in Germany;
  • in California;
  • traveling;
  • using your app internationally.

Privacy logic should follow applicable user context and platform requirements, not the developer's office address.

Google's current Flutter privacy documentation also supports signals such as restricted data processing and Global Privacy Platform signals for applicable US state rules.

Do not hard-code a single global consent assumption.

The UI should not individually decide advertising privacy.

Create a privacy/consent layer.

Conceptually:

enum AdsConsentState {
  unknown,
  personalizedAllowed,
  nonPersonalizedOnly,
  adsRestricted,
}
 
abstract interface class AdsPrivacyService {
  Future<AdsConsentState> refresh();
  Future<void> showPrivacyOptionsIfRequired();
}

Now the startup coordinator can decide when ad initialization is safe.

That is much easier to maintain than scattering flags across banner/interstitial widgets.

iOS privacy deserves its own release testing

iOS can involve:

  • App Tracking Transparency depending on tracking behavior;
  • SKAdNetwork configuration for relevant ad partners;
  • privacy manifests and SDK declarations;
  • consent flows.

The exact requirements depend on what your app and ad partners do.

AppLovin's current Flutter integration guide, for example, explicitly calls out iOS privacy configuration, SKAdNetwork setup and consent/data APIs.

Do not copy Android configuration and assume iOS is done.

Test the complete production flow on a physical iPhone.

Part 3: app-ads.txt and AdMob app readiness

For AdMob, app setup now has a publishing dependency beyond the SDK.

Google's current help documentation says new apps need app-ads.txt verification as part of app verification/readiness before they can fully serve ads.

The file belongs at the root of the developer website associated with the store listing.

Example location:

https://example.com/app-ads.txt

Google's authorized-sellers documentation describes app-ads.txt as the mechanism for declaring which sellers are allowed to sell your app inventory.

Production checklist for app-ads.txt

Verify:

  1. your store listing contains the correct developer website;
  2. the domain resolves publicly;
  3. /app-ads.txt returns HTTP 200;
  4. robots.txt does not block it;
  5. required seller entries are correctly formatted;
  6. there are no hidden redirects to an unrelated domain;
  7. AdMob successfully verifies the file.

Google says new apps created after January 2025 that are not verified can face limited serving.

This is therefore not an optional launch-day detail for a new AdMob app.

Separate SDK integration from monetization readiness

A developer can have perfect Flutter code while production ads still do not serve fully because:

  • app is not linked correctly;
  • app-ads.txt is missing;
  • readiness review is pending;
  • consent is not configured;
  • account has policy restrictions;
  • ad unit is new;
  • demand is unavailable.

Do not debug every no-fill as a Dart bug.

Your observability should distinguish:

SDK integration error
vs
no-fill
vs
account/readiness state
vs
consent restriction
vs
network timeout

Part 4: mediation in Flutter

Mediation lets several ad sources participate in monetizing the same app inventory.

You can use:

  • Google AdMob mediation;
  • AppLovin MAX;
  • Unity LevelPlay;
  • other mediation systems.

The best mediator is not determined by Flutter itself.

Evaluate:

  • network support;
  • formats;
  • plugin quality;
  • adapter maintenance;
  • bidding relationships;
  • reporting;
  • debugging;
  • privacy configuration;
  • your traffic.

Google mediation with Flutter

Google's current Flutter mediation guide requires you to integrate the ad format first and then add mediation adapters/network dependencies.

A critical current requirement is initialization.

Google says to initialize the Mobile Ads Flutter plugin and wait for initialization to complete before loading mediated inventory so adapters can participate in the first request.

Bidding adapters require explicit Google Mobile Ads initialization.

Third-party test mode still matters

Google's test-ad guide warns that mediated ads may not display the normal Google Test Ad label.

You are responsible for enabling safe test behavior for each mediated network.

That means a mediation QA plan needs network-by-network verification.

Do not let two systems refresh the same banner

Google's mediation guidance warns that when using mediated banner ads, third-party source auto-refresh should be disabled where required so you do not have competing refresh systems.

Why?

Because:

mediator refresh
+
network refresh
=
unexpected duplicate request behavior

One layer should own the placement lifecycle.

AppLovin MAX for Flutter

AppLovin's current Flutter package is applovin_max.

The version checked on 20 September 2026 is 4.6.4.

Install it with:

flutter pub add applovin_max

Current AppLovin documentation initializes the SDK once with the account SDK key:

import 'package:applovin_max/applovin_max.dart';
 
Future<void> initializeMax(String sdkKey) async {
  final configuration = await AppLovinMAX.initialize(sdkKey);
 
  // The SDK is initialized.
  // Begin loading configured ad units here.
}

Do not embed private server secrets in Flutter.

Use only the client-side identifier/SDK key intended by the provider for mobile integration.

AppLovin recommends initialization on startup so mediated networks have time to cache assets, especially video.

Why MAX may be used in a Flutter app

MAX becomes relevant when you want:

  • mediation;
  • bidding;
  • multiple demand partners;
  • rewarded/interstitial-heavy monetization;
  • centralized ad-unit configuration.

It is not inherently a higher-paying replacement for AdMob.

That question requires your own production data.

See the separate guide: Best AdMob Alternatives in India in 2026.

Unity LevelPlay for Flutter

The current Unity package is:

unity_levelplay_mediation

The checked stable version is 9.2.0.

The older package name ironsource_mediation is deprecated.

Unity's current changelog says the 9.2.0 Flutter release adds LevelPlayPrivacySettings APIs for GDPR, CCPA and COPPA-related configuration.

The current package supports Android and iOS.

Install through the current pub.dev package and follow Unity's dashboard/network setup for mediated demand.

Why package-renaming history matters

An old tutorial may still tell you:

flutter pub add ironsource_mediation

That is stale in 2026.

This is exactly why integration articles should reference current publisher documentation rather than blindly copying older code.

Theaimart ADX Flutter SDK

Theaimart publishes the Flutter package:

theaimart_adx

The current public API documentation checked for this article lists version 1.0.0.

Install:

flutter pub add theaimart_adx

The published SDK documentation describes support for:

  • Android;
  • iOS;
  • web;
  • Windows;
  • macOS;
  • Linux.

This is a different platform profile from the mobile-only Flutter plugins above.

Theaimart ADX banner example

The current official repository documents a BannerAd widget:

adx_banner_example.dart
import 'package:flutter/material.dart';
import 'package:theaimart_adx/theaimart_adx.dart';
 
class MonetizedScreen extends StatelessWidget {
  const MonetizedScreen({super.key});
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          const Expanded(
            child: Center(
              child: Text('Application content'),
            ),
          ),
          SafeArea(
            top: false,
            child: BannerAd(
              apiKey: 'pk_your_publisher_key',
              slotId: 'YOUR_SLOT_ID',
              onAdLoaded: (ad) {
                debugPrint('Filled by ${ad.source}');
              },
              onAdFailed: (reason) {
                debugPrint('No fill: $reason');
              },
            ),
          ),
        ],
      ),
    );
  }
}

The repository explicitly says client-distributed apps should use only public publisher keys beginning with pk_.

Do not put administrative credentials, private infrastructure tokens, advertiser billing credentials or signing keys into a Flutter binary.

ADX viewability behavior

The current ADX SDK contract documents a standard viewable impression as:

  • at least 50% of the ad visible;
  • for at least one continuous second.

Managed UI SDKs are expected to measure this automatically.

The SDK documentation also says advertising failures should fail closed and must not interrupt the host application's primary functionality.

That is a good general principle for every ad provider.

Your app should still work when:

  • network is offline;
  • ad request times out;
  • creative is malformed;
  • no fill occurs;
  • tracking fails.

Cross-platform Flutter changes the ad strategy

A Flutter project may compile to:

  • Android;
  • iOS;
  • web;
  • Windows;
  • macOS;
  • Linux.

But most mobile ad SDKs do not cover all six.

Google's google_mobile_ads package is for Android and iOS.

AppLovin MAX Flutter is Android/iOS.

Unity LevelPlay Flutter is Android/iOS.

Theaimart ADX currently documents broader Flutter platform coverage.

This means your abstraction can also become a platform router.

Conceptually:

AdService createAdService() {
  if (isMobile) {
    return MobileAdService();
  }
 
  if (isDesktopOrWeb) {
    return CrossPlatformAdService();
  }
 
  return NoAdsService();
}

The actual provider choice should depend on supported platforms, demand and economics.

Do not assume one SDK can monetize every Flutter target simply because the application code is shared.

Part 5: lifecycle engineering

Ads are stateful objects with native resources.

Flutter widgets are disposable.

That creates lifecycle problems if you treat an ad like ordinary immutable UI data.

Dispose loaded ads

For Google banners and full-screen ads, dispose objects after they are no longer useful.

Common failure patterns include:

  • retaining an ad after screen disposal;
  • loading duplicates on every rebuild;
  • showing a full-screen ad twice;
  • callback tries setState after widget is gone;
  • orphaned ad objects survive navigation.

Do not load from build()

Flutter build methods can run frequently.

Never start a network ad load simply because build() executed.

Use:

  • initState;
  • didChangeDependencies when layout information is required;
  • controller/service initialization;
  • explicit preload events.

Guard async callbacks with mounted

If a callback will update a StatefulWidget after asynchronous work, verify the widget is still mounted.

Otherwise navigation can turn a successful ad callback into a Flutter exception.

Full-screen ads need state machines

Useful states include:

idle
loading
ready
showing
cooldown
failed

A boolean such as isLoaded often becomes insufficient once retries, navigation and concurrent requests appear.

Prevent duplicate rewarded grants

The reward callback can touch valuable user state.

Make granting idempotent.

For server-side rewards, use a transaction/reward identifier and reject duplicate processing.

For local-only low-value rewards, still protect against accidental double callback processing.

Conceptually:

bool _rewardGranted = false;
 
Future<void> grantOnce() async {
  if (_rewardGranted) return;
  _rewardGranted = true;
 
  await wallet.addCredits(1);
}

This is only a local guard, not a fraud-resistant payment system.

Handle no-fill as a normal outcome

No-fill is not necessarily an exception.

Your UI should not display:

  • permanent spinner;
  • blank black rectangle;
  • retry loop;
  • error popup.

Instead:

ad unavailable
→ collapse optional placement
→ continue app normally

The ADX repository explicitly documents this fail-closed behavior, and it is a good pattern across networks.

Retries need backoff

Do not implement:

no fill
→ immediately request again
→ no fill
→ immediately request again
→ forever

This wastes network/battery and can look like abusive request behavior.

Use controlled retries or wait for the next natural opportunity.

For a full-screen ad, loading the next unit after dismissal is usually enough.

Part 6: analytics and paid-event measurement

A monetization integration is incomplete if you can only see aggregate revenue in an ad-network dashboard.

You want to connect advertising outcomes with product behavior.

Useful dimensions include:

  • placement;
  • format;
  • app version;
  • platform;
  • country;
  • user segment;
  • session number;
  • premium/free state;
  • mediation source;
  • revenue value;
  • revenue precision where exposed;
  • load latency;
  • show success/failure.

Google supports impression-level ad revenue callbacks, which can be connected to your analytics system.

Unity LevelPlay also documents impression-level revenue integration for Flutter.

The principle is provider-independent:

ad impression
→ paid/revenue callback
→ normalized internal event
→ analytics warehouse

Normalize provider-specific revenue events

Create one internal event shape.

For example:

ad_revenue_event.dart
class AdRevenueEvent {
  const AdRevenueEvent({
    required this.provider,
    required this.placement,
    required this.format,
    required this.currency,
    required this.value,
    this.network,
  });
 
  final String provider;
  final String placement;
  final String format;
  final String currency;
  final double value;
  final String? network;
}

Now product analytics does not depend on Google's or MAX's naming.

That makes provider experiments much easier.

Track revenue per user, not only eCPM

Network dashboards emphasize ad metrics.

Product teams should also care about:

ad revenue per DAU
revenue per session
revenue per retained user
30-day ad LTV

Why?

Because an ad format can have a high eCPM and still hurt the business.

Example:

Placement A:
higher eCPM
lower D7 retention
 
Placement B:
lower eCPM
higher D7 retention
higher lifetime revenue

A network dashboard alone cannot answer that question.

Your app analytics can.

Measure AI cost beside ad revenue

For an AI-powered Flutter app, connect:

user/session
→ ad revenue
→ model/API cost
→ contribution margin

Suppose a rewarded ad unlocks one generation.

The event chain can be:

rewarded_ad_started
rewarded_ad_completed
reward_granted
ai_request_started
ai_request_cost_recorded
user_returned_next_day

Now you can answer:

Does rewarded AI usage make money, lose money or improve retention enough to justify the subsidy?

That is much better than simply counting rewarded completions.

Part 7: production testing

An ad integration needs more than widget tests.

Use several layers.

Unit-test monetization policy

Test:

  • frequency caps;
  • premium no-ads behavior;
  • placement eligibility;
  • reward idempotency;
  • cooldown logic;
  • fallback routing.

These do not need a real ad SDK.

Widget-test UI fallback

Test:

  • banner unavailable;
  • banner loads;
  • user has Pro;
  • screen disposes before callback;
  • layout remains usable without ads.

Real-device integration tests

Test on physical Android and iOS devices:

  • cold start;
  • warm resume;
  • offline mode;
  • slow connection;
  • orientation change;
  • navigation while loading;
  • background during full-screen ad;
  • consent flow;
  • test rewarded completion;
  • dismissal;
  • no-fill;
  • app kill and restart.

Test low-end Android hardware

Flutter ad integrations bridge native SDKs, video, WebViews and rendering.

A setup that feels fine on a flagship can produce jank on an older phone.

Test:

  • startup time;
  • memory;
  • scrolling;
  • inline banners;
  • video creative;
  • screen transition after dismissal.

Google's banner guidance specifically notes that inline scrolling banners can perform worse on older Android versions/devices and recommends choosing formats appropriately.

Use ad inspector and network debugging tools

Google provides Ad Inspector for inspecting requests and mediated sources.

Current Flutter documentation supports:

  • in-context testing;
  • out-of-context ad-unit testing;
  • single ad-source testing.

In-context tests are especially valuable because they include the real parameters from the app flow.

AppLovin and Unity also provide integration/debug tooling.

Use the mediator's diagnostics before blaming demand.

Common integration failures include:

  • wrong application ID;
  • wrong ad unit;
  • adapter not initialized;
  • missing network dependency;
  • dashboard mapping error;
  • consent misconfiguration;
  • app-ads.txt authorization issue.

Part 8: monetization configuration

Do not hard-code every monetization decision in Dart.

A remote configuration system can safely control product-level settings such as:

ads_enabled
interstitial_enabled
rewarded_enabled
minimum_interstitial_gap_seconds
max_daily_interstitials
app_open_enabled
rollout_percentage

This gives you a kill switch.

If a release causes:

  • crashes;
  • bad creative behavior;
  • excessive latency;
  • user complaints;

you can disable a placement without waiting for another store review.

Do not remotely change prohibited behavior

Remote config does not bypass:

  • app-store policies;
  • consent requirements;
  • ad-network policies;
  • review declarations.

It is an operational control, not a policy loophole.

Keep identifiers in configuration

Separate:

  • development test IDs;
  • staging IDs;
  • production Android IDs;
  • production iOS IDs.

For example:

class MonetizationConfig {
  const MonetizationConfig({
    required this.interstitialId,
    required this.rewardedId,
    required this.bannerId,
  });
 
  final String interstitialId;
  final String rewardedId;
  final String bannerId;
}

Then construct the appropriate configuration for environment/platform.

This is safer than duplicating Platform.isAndroid checks across twenty widgets.

Public SDK keys are not the same as private secrets

Some mobile SDKs intentionally require public identifiers in the client.

That does not mean every credential is safe to embed.

Theaimart ADX explicitly documents that client applications should use public publisher keys beginning with pk_.

Other administrative or billing credentials must not be distributed.

General rule:

credential intended for untrusted mobile client
→ may be embedded according to provider docs
 
server secret / admin token / signing key
→ never embed

A compiled Flutter app is not a secret store.

Assume values in the client can be recovered.

Part 9: choosing between AdMob, MAX, LevelPlay and ADX

This article is not a network payout ranking.

Use architecture and traffic requirements.

Start with Google Mobile Ads when

  • Android/iOS are your targets;
  • you want direct AdMob integration;
  • you want a widely documented Flutter path;
  • you may use AdMob mediation;
  • you need banner/native/rewarded/interstitial/app-open formats.

Evaluate MAX when

  • mediation is central to the strategy;
  • you want the MAX control layer;
  • your app uses a lot of rewarded/interstitial inventory;
  • supported demand partners match your needs.

Evaluate LevelPlay when

  • you want Unity's mediation stack;
  • games/rewarded monetization are important;
  • its mediated networks and reporting fit your operation.

Evaluate ADX when

  • you want to test Theaimart ADX as a demand/monetization route;
  • your Flutter project also targets web/desktop platforms that the published ADX SDK supports;
  • its current formats and demand fit your product.

The only reliable economic decision comes from your own production data.

For network-level comparison methodology, see Best AdMob Alternatives in India in 2026.

Part 10: India-specific Flutter monetization considerations

A Flutter developer in India should avoid two opposite mistakes.

Mistake: assuming Indian traffic is worthless

India is a massive and diverse audience.

A business productivity app, English finance app, casual game and regional-language entertainment product have different advertiser value.

Measure your actual segments.

Mistake: copying US monetization assumptions

Your users may have different:

  • willingness to pay;
  • device distribution;
  • data/network conditions;
  • session behavior;
  • language;
  • advertiser demand.

Optimize locally.

Android may dominate your traffic

For many India-focused products, Android can be the primary audience.

That makes Android QA especially important:

  • low-memory devices;
  • older OS versions;
  • slower storage;
  • network variability;
  • manufacturer-specific behavior.

Do not benchmark ad UX only on the developer's premium test device.

Revenue can be seasonal

Advertiser demand moves with:

  • festivals;
  • sales periods;
  • product launches;
  • financial quarters;
  • campaign budgets.

Do not declare a provider winner from one unusually strong week.

Part 11: ad placement examples

Example: AI image app

Bad:

prompt typed
→ interstitial
→ generation
→ interstitial
→ result

Better:

prompt
→ generation
→ result
 
optional:
watch rewarded ad
→ earn another generation

Whether the rewarded model is profitable depends on generation cost and ad revenue.

Example: PDF utility

Possible flow:

select file
→ process
→ result
→ optional interstitial after completion

Do not block the file-selection or save action with a surprise ad.

Example: game

Possible flow:

play level
→ level complete
→ occasional interstitial
→ next level
 
death
→ optional rewarded revive

Natural transitions give full-screen formats a clear place.

Example: news/content feed

Possible flow:

content cards
→ native ad unit
→ more content

A native placement should be visibly an ad and should not imitate editorial content deceptively.

Frequency design

Do not ask:

How often can the SDK show an ad?

Ask:

How often can the user experience tolerate this placement while maintaining retention?

You can maintain a placement policy:

class PlacementPolicy {
  const PlacementPolicy({
    required this.minimumSessionNumber,
    required this.cooldown,
    required this.dailyLimit,
  });
 
  final int minimumSessionNumber;
  final Duration cooldown;
  final int dailyLimit;
}

Then evaluate eligibility based on application state.

This is easier to A/B test than hard-coded if-statements.

Premium users and ad removal

If a user buys an ad-free plan, eliminate ad requests as early as possible.

Do not:

load ads
→ discover user is Pro
→ hide widget

Prefer:

resolve entitlement
→ if Pro: no ad SDK request for that placement
→ if Free: monetize

Benefits include:

  • less network traffic;
  • less battery use;
  • clearer privacy behavior;
  • fewer unnecessary requests;
  • simpler premium promise.

Depending on your application, the core SDK may still initialize for another reason, but optional ad loads should respect entitlement.

Ads should never block core application availability

Your application should work when ad infrastructure is down.

Design fallback behavior.

failed/no fill
→ collapse slot

Interstitial

not ready
→ continue transition

Do not hold a user hostage waiting for an optional interstitial.

Rewarded

Rewarded is different because the user explicitly requested a value exchange.

If no ad is available:

show "Reward currently unavailable"
→ offer normal non-reward path

Do not promise the reward and then silently fail.

Part 12: common Flutter ad integration mistakes

1. Loading ads inside build()

This can create repeated requests.

2. Forgetting dispose()

Ads can hold native resources.

3. Using live ads during development

Use test inventory.

4. Reusing a full-screen ad object

Interstitial/rewarded objects are generally one-show resources.

5. No frequency caps

A technically valid integration can still destroy retention.

6. Granting valuable rewards entirely from an easily modified client

Use stronger verification for valuable entitlements.

7. Treating no-fill as a crash/error condition

No-fill is normal.

8. Integrating mediation without adapter testing

Every network needs validation.

9. Copying old package names

Unity's old ironsource_mediation Flutter package is deprecated; current integrations use unity_levelplay_mediation.

10. Hard-coding one provider throughout the UI

Use an AdService boundary.

11. Ignoring app-ads.txt until production

AdMob verification/readiness can affect serving.

12. Adding five SDKs before measuring one

Establish a baseline.

13. No revenue analytics

If you cannot tie paid impressions to placements/users, optimization is guesswork.

14. Showing interstitials at user-hostile moments

Use natural transitions.

15. Assuming Flutter means identical configuration on Android and iOS

Flutter shares Dart code, not all platform policy and native configuration.

Production release checklist

Before shipping ads in a Flutter app, verify:

Frequently asked questions

Flutter app mein ads kaise lagaye?

The simplest Android/iOS route is to install a supported Flutter ad SDK such as google_mobile_ads, configure the native application identifiers, initialize the SDK, create an ad unit, load the chosen format and render/show it at an appropriate product placement.

For production, also handle test ads, consent, app readiness, app-ads.txt, lifecycle, analytics and frequency caps.

Flutter ke liye best ads SDK konsa hai?

There is no universal best SDK.

Google Mobile Ads is a common direct starting point for Android/iOS. AppLovin MAX and Unity LevelPlay are major mediation options. Theaimart ADX provides a separate Flutter monetization route and documents broader Flutter platform support.

Choose from platform support, formats, demand, mediation needs and your own measured revenue.

google_mobile_ads ka latest version kya hai?

When this article was checked on 20 September 2026, pub.dev listed google_mobile_ads 9.1.0 as the current stable version.

Do not hard-code that assumption months later; check pub.dev before installing.

Flutter mein rewarded ads kaise implement kare?

Using Google Mobile Ads, load RewardedAd ahead of time, attach lifecycle callbacks, call show when the user intentionally chooses the reward and grant the value from onUserEarnedReward. For valuable rewards, consider server-side verification.

Flutter mein interstitial kab dikhana chahiye?

At natural transition points such as after completing a task or between game levels.

Do not unexpectedly block critical buttons or core actions.

For Google Mobile Ads, adaptive banners are generally the responsive approach documented for modern Flutter layouts. Anchored adaptive banners fit fixed top/bottom placement, while inline adaptive banners are designed for scrolling content.

Kya Flutter web mein AdMob chalega?

The google_mobile_ads Flutter package is documented for Android and iOS, not Flutter web.

For a Flutter project targeting web or desktop, use a provider or web monetization solution that explicitly supports those targets. Theaimart ADX currently documents Flutter support across Android, iOS, web, Windows, macOS and Linux.

Kya ek Flutter app mein multiple ad networks use kar sakta hoon?

Yes.

A common approach is mediation through AdMob, AppLovin MAX or Unity LevelPlay rather than manually scattering multiple network SDK calls through the app.

AdMob mediation Flutter mein kaise work karti hai?

You integrate Google Mobile Ads and the desired formats, configure mediation in the AdMob interface and add the required partner adapters/dependencies. Google says the Mobile Ads SDK should be initialized and mediation adapters should be ready before the first mediated request.

AppLovin MAX Flutter kaise install kare?

The current official command is:

flutter pub add applovin_max

Then initialize AppLovinMAX once using the account SDK key and configure ad units/networks according to the current MAX documentation.

Unity LevelPlay ka current Flutter package kya hai?

As of this article, the package is unity_levelplay_mediation. The former ironsource_mediation package is deprecated.

Theaimart ADX Flutter SDK ka package kya hai?

The public package is theaimart_adx.

The official repository currently documents:

flutter pub add theaimart_adx

and a BannerAd widget using a public publisher key and slot ID.

Kya app ke source code mein ADX key safe hai?

Theaimart's current SDK documentation specifically says client-distributed apps should use the public publisher key type beginning with pk_.

Private/admin/billing/signing credentials should never be embedded in the Flutter application.

Ad show na ho toh kya retry loop chalana chahiye?

No uncontrolled loop.

No-fill is a normal outcome. Retry at a later natural opportunity or use controlled backoff.

Kya ads se Flutter app slow ho sakta hai?

Potentially.

Native SDK initialization, video assets, WebViews, mediation adapters and extra dependencies can affect startup, memory and rendering.

Measure on low-end real devices, not only a flagship development phone.

Ads se kitna paisa milega?

There is no fixed Flutter or India rate.

Revenue depends on demand, format, geography, audience, fill, placement and auction competition. Measure eCPM together with fill, impressions, ARPDAU and retention.

Final architecture

A maintainable Flutter monetization stack looks like:

                    ┌─────────────────────┐
                    │   Flutter screens   │
                    └──────────┬──────────┘
                               │
                    ┌──────────▼──────────┐
                    │ Placement policies  │
                    │ frequency / premium │
                    └──────────┬──────────┘
                               │
                    ┌──────────▼──────────┐
                    │     AdService       │
                    └──────────┬──────────┘
                               │
          ┌────────────────────┼────────────────────┐
          │                    │                    │
     Google/AdMob          MAX/LevelPlay       Theaimart ADX
          │                    │                    │
          └────────────────────┼────────────────────┘
                               │
                    ┌──────────▼──────────┐
                    │ Revenue analytics   │
                    │ retention + LTV     │
                    └─────────────────────┘

The provider can change.

The application architecture does not have to.

That is the main difference between simply putting ads in a Flutter app and building a monetization system that can survive real production traffic.

If you are beginning with Google demand, use the current Google Mobile Ads Flutter documentation. If you are evaluating multiple networks, see AdMob Alternatives in India. For broader monetization strategy beyond advertising, read How to Monetize a Mobile App in India. Flutter developers who want to evaluate Theaimart's own SDK can use the ADX developer hub.

If your Flutter app is an AI product, How to monetize an AI app with ads covers where ads should and should not go.