MAX Dynamic Bid Integration

  • Updated

MAX supports the ability to ingest price floors on a per ad request basis. You can run your in-house auction to determine the winning bid and call MAX as your ultimate demand source in the supply chain.

If bids returned by MAX win the auction, you are expected to show them based on the requirements listed below.

This is an invite-only integration method that requires further approval from AppLovin account teams. If you implement this feature, submit your app to your dedicated account team for a successful transition. Incorrect implementations will be disabled immediately.

Ad Load Lifecycle

  • You run the in-house auction and determine a winning bid to be used as a floor for MAX.
    • If the in-house stack returns no-fill, the MAX ad load request does not have a floor. The bid that MAX returns with the floor passed wins the auction, and clears.
    • If the in-house stack has a winning bid, that value is passed to MAX as a floor in the ad load request to MAX.
      • MAX runs the auction with the buyers enabled in the MAX dashboard.
      • If MAX returns a bid higher than the floor passed, you must show the bid. Ads shown outside of the ad expiration window might not be considered payable impressions.
      • If the floor is not met, MAX returns a no-fill response.
      • When MAX returns no-fill, show the original in-house bid that you used as a floor for the ad request.
  • MAX reports only show data associated with winning bids that were returned, cached, and cleared. Requests with no fill are filtered from reports.


  • Disable banner auto-refresh (for instructions, see “Banner Ads”). The developer should control refresh, which should happen not less than five seconds apart.
  • Disable sequential caching. Only one ad request per ad format is expected to be in flight when calling MAX.
  • Do not send multiple requests per opportunity. Send only one ad load request per ad impression opportunity. Do not send multiple ad requests either in parallel, or consecutively for the same user and impression opportunity with different price floors. If you use MAX via dynamic bid, disable the banner/MREC auto-refresh feature and the interstitial/rewarded-video sequential caching feature.
  • Each ad load opportunity must be unique, following the natural progression of the user within the session. If MAX does not return a bid (no-fill response), retry ad loads manageably and within a reasonable window. AppLovin recommends that you request a new ad by means of an algorithm that resembles the exponential retry logic snippet on the “Interstitial Ads” page.
  • Do not preemptively request an ad load with an average or predicted CPM value. The floor you submit to MAX must be the winning bid from the in-house mediation. If you set no floor, the bid MAX returns is the winning bid and is expected to show.
  • Do not parallel-process MAX ad load requests with your in-house mediation to pick the highest bid. Preserve the hierarchy of the ad load lifecycle with the correct signals. If the bid returned is not shown due to another auction or a price point compared, your access to demand will be disabled.
  • Show the winning bid that MAX returns. Do not pull it into another auction, or cache it for a later time to be used in another opportunity. The MAX winning bid is the final bid for the ad load opportunity.
  • AppLovin SDK automatically clears all cached ads within four hours for most ad formats. Depending on which demand source you are mediating via MAX, the winning bid can expire faster. Note that developers who use the manual native ads integration are responsible for ad expiration. Ads shown after four hours will not be payable.
  • If the cached bid from AppLovin expires, run a new auction starting with your in-house stack. Reusing the previous auction’s floor, and setting artificially calculated price floors to increase yield, are both prohibited.
  • Do not implement a timeout on MAX response times.
  • Ads shown outside of the ad expiration window might be invalidated. The SDK callback-based impression count shown in the AppLovin dashboard and the final billable impressions might vary. Banners, MREC, and native ads are expected to be shown within a few minutes after the ad response is returned. Interstitial and rewarded video are expected to show within four hours.
  • Do not send traffic from the following geos:
    • Afghanistan
    • Albania
    • Algeria
    • Angola
    • Azerbaijan
    • Bangladesh
    • Barbados
    • Belarus
    • Benin
    • Bhutan
    • Bolivia
    • Brunei Darussalam
    • Burkina Faso
    • Congo, the Democratic Republic of the
    • Côte D’Ivoire
    • Cuba
    • Dominican Republic
    • Ecuador
    • El Salvador
    • Ethiopia
    • Fiji
    • Gabon
    • Guatemala
    • Guyana
    • Haiti
    • Honduras
    • Iran
    • Iraq
    • Jordan
    • Kazakhstan
    • Kenya
    • Kosovo
    • Kyrgyzstan
    • Latvia
    • Libyan Arab Jamahiriya
    • Macedonia, the Former Yugoslav Republic of
    • Mali
    • Mauritania
    • Mauritus
    • Mongolia
    • Montenegro
    • Morocco
    • Mozambique
    • Myanmar
    • Nepal
    • Nicaragua
    • Papua New Guinea
    • Paraguay
    • Senegal
    • Serbia
    • Somalia
    • Sri Lanka
    • Sudan
    • Syria
    • Tajikistan
    • Togo
    • Tunisia
    • Uzbekistan
    • Venezuela
    • Yemen
    • Zambia
    • Zimbabwe

    Sample Code

    The following code snippets show you how to set the price floor for MAX ads (replace value with a string that expresses the CPM price floor in U.S. dollars, for example: 5.00 = $5/mille = ½¢/bid. This value has a maximum precision of eight decimal places.

    This price floor applies to all demand sources that are based on the CPM value (e.g. direct sold, traditionally mediated network lines, SDK-bidders, Exchange DSPs):

    • // Interstitial Ad
      MaxSdk.SetInterstitialExtraParameter("ad-unit-ID", "jC7Fp", "value");
      // Rewarded Ad
      MaxSdk.SetRewardedAdExtraParameter("ad-unit-ID", "jC7Fp", "value");
      // Banner Ad
      MaxSdk.SetBannerExtraParameter("ad-unit-ID", "jC7Fp", "value");
      // MRec Ad
      MaxSdk.SetMRecExtraParameter("ad-unit-ID", "jC7Fp", "value");
    • // Interstitial Ad
      interstitialAd = new MaxInterstitialAd( "ad-unit-ID", this );
      interstitialAd.setExtraParameter( "jC7Fp", "value" );
      // Rewarded Ad
      rewardedAd = MaxRewardedAd.getInstance( "ad-unit-ID", this );
      rewardedAd.setExtraParameter( "jC7Fp", "value" );
      // Banner Ad
      bannerAd = new MaxAdView( "ad-unit-ID", this );
      bannerAd.setExtraParameter( "jC7Fp", "value" );
      // MRec Ad
      mrecAd = new MaxAdView( "ad-unit-ID", MaxAdFormat.MREC, this );
      mrecAd.setExtraParameter( "jC7Fp", "value" );
      // Native Ad
      nativeAdLoader = new MaxNativeAdLoader( "ad-unit-ID", this );
      nativeAdLoader.setExtraParameter( "jC7Fp", "value" );
    • // Interstitial Ad
      var interstitialAd = MaxInterstitialAd( "ad-unit-ID", this )
      interstitialAd.setExtraParameter( "jC7Fp", "value" )
      // Rewarded Ad
      var rewardedAd = MaxRewardedAd.getInstance( "ad-unit-ID", this )
      rewardedAd.setExtraParameter( "jC7Fp", "value" )
      // Banner Ad
      var bannerAd = MaxAdView( "ad-unit-ID", this )
      bannerAd.setExtraParameter( "jC7Fp", "value" )
      // MRec Ad
      var mrecAd = MaxAdView( "ad-unit-ID", MaxAdFormat.MREC, this )
      mrecAd.setExtraParameter( "jC7Fp", "value" )
      // Native Ad
      var nativeAdLoader = MaxNativeAdLoader( "ad-unit-ID", this )
      nativeAdLoader.setExtraParameter( "jC7Fp", "value" )
    • // Interstitial Ad
      self.interstitialAd = [[MAInterstitialAd alloc] initWithAdUnitIdentifier: @"ad-unit-ID"];
      [self.interstitialAd setExtraParameterForKey:@"jC7Fp" value:@"value"];
      // Rewarded Ad
      self.rewardedAd = [MARewardedAd sharedWithAdUnitIdentifier: @"ad-unit-ID"];
      [self.rewardedAd setExtraParameterForKey:@"jC7Fp" value:@"value"];
      // Banner Ad
      self.bannerAd = [[MAAdView alloc] initWithAdUnitIdentifier: @"ad-unit-ID"];
      [self.bannerAd setExtraParameterForKey:@"jC7Fp" value:@"value"];
      // MRec Ad
      self.mrecAd = [[MAAdView alloc] initWithAdUnitIdentifier: @"ad-unit-ID" adFormat: MAAdFormat.mrec ];
      [self.mrecAd setExtraParameterForKey:@"jC7Fp" value:@"value"];
      // Native Ad
      self.nativeAdLoader = [[MANativeAdLoader alloc] initWithAdUnitIdentifier: @"ad-unit-ID"];
      [self.nativeAdLoader setExtraParameterForKey:@"jC7Fp" value:@"value];
    • // Interstitial Ad
      let interstitialAd = MAInterstitialAd(adUnitIdentifier: "ad-unit-ID")
      interstitialAd.setExtraParameterForKey("jC7Fp", value: "value")
      // Rewarded Ad
      let rewardedAd = MARewardedAd.shared(withAdUnitIdentifier: "ad-unit-ID")
      rewardedAd.setExtraParameterForKey("jC7Fp", value: "value")
      // Banner Ad
      let bannerAd = MAAdView(adUnitIdentifier: "ad-unit-ID")
      bannerAd.setExtraParameterForKey("jC7Fp", value: "value")
      // MRec Ad
      let mrecAd = MAAdView(adUnitIdentifier: "ad-unit-ID", adFormat: MAAdFormat.mrec)
      mrecAd.setExtraParameterForKey("jC7Fp", value: "value")
      // Native Ad
      let nativeAdLoader = MANativeAdLoader(adUnitIdentifier: "ad-unit-ID")
      nativeAdLoader.setExtraParameterForKey("jC7Fp", value: "value")