Prebid Mobile SDK Integration: Combining GMA Next-Gen SDK, OpenRTB S2S, and Custom Native Rendering

Unlike browser-based header bidding wrappers where Prebid.js dispatches dozens of concurrent XMLHttpRequests directly from the client device, the Prebid

Macro 3D mobile motherboard illustration showing a glass Prebid Mobile SDK chip communicating via a vertical cyan laser with a cloud prism to route golden key-value pulses to the display controller.

Unlike browser-based header bidding wrappers where Prebid.js dispatches dozens of concurrent XMLHttpRequests directly from the client device, the Prebid Mobile SDK operates strictly as a lightweight OpenRTB 2.6 client that emits a single multiplexed HTTP POST payload to a Prebid Server (PBS-Go or PBS-Java) endpoint. On cellular networks where radio state transitions (RRC_IDLE to RRC_CONNECTED) and TLS 1.3 handshakes introduce 150 to 300 milliseconds of baseline round-trip latency, shifting bidder fan-out to cloud infrastructure preserves device battery life, eliminates main-thread UI contention, and prevents TCP socket exhaustion inside the host application.

Mobile engineering and AdOps teams now face a simultaneous architectural shift across the in-app programmatic stack. On Android, publishers are migrating from legacy single-threaded Google Mobile Ads (GMA) libraries toward the coroutine-native GMA Next-Gen SDK to eliminate Application Not Responding (ANR) exceptions during ad initialization and rendering. At the same time, high-ARPDAU applications require server-to-server (S2S) OpenRTB demand orchestration alongside custom native rendering pipelines that bypass slow WebView containers altogether. Executing this stack requires precise synchronization between client-side SDK callbacks, server-side stored request templates, and Open Measurement SDK (OM SDK v1.5) viewability verification.

At Sky Boosts, our engineering teams architect high-yield mobile app monetization pipelines across iOS and Android by combining managed Prebid Server infrastructure with Google Ad Manager (GAM 360) and AdX demand. Operating exclusively on 100% Google-friendly, HUMAN and Pixalate IVT-clean inventory with zero restricted categories (no gambling, adult, alcohol, or tobacco demand), we provide publishers with predictable Net-30 and Net-60 payment terms alongside full transparency into auction mechanics. The sections below detail the production implementation patterns required to unify Prebid Mobile, the GMA Next-Gen SDK, and custom native rendering.

Architecture of Prebid Mobile: Config IDs and Prebid Server Stored Requests

The foundational design principle of Prebid Mobile is the separation of client-side signal collection from server-side auction execution. When an iOS (PrebidMobile.xcframework) or Android (org.prebid:prebid-mobile-sdk) application initializes an ad unit, the SDK does not hold hardcoded SSP endpoint URLs, seat IDs, or bidder-specific adapter logic in the compiled binary. Instead, as documented in the official Prebid Mobile getting started documentation, Prebid Mobile SDKs require a Prebid Server host where each mobile placement maps to a server-side stored impression Config ID, enabling server-side adapter updates and Prebid Server Price Floors without app store binary resubmissions.

Motherboard schematic showing the Prebid Mobile SDK chip requesting bids from Prebid Server Cloud and passing returned targeting key-values into the Primary Ad Server SDK chip to render the screen.

When the Prebid Mobile SDK triggers a fetchDemand call to the /openrtb2/auction endpoint on Prebid Server, the outgoing JSON payload contains two distinct stored request identifiers: an Account-Level Stored Request ID (ext.prebid.storedrequest.id) and an Impression-Level Stored Request ID (imp[].ext.prebid.storedrequest.id). Prebid Server resolves both identifiers against a low-latency distributed cache or database backend before fanning out bid requests to participating SSP partners and tier-1 DSPs:

  • Account-Level Stored Request (hostAccountId): Defines global auction rules for the application, including the master timeout budget (tmax), currency conversion tables, SupplyChain (source.ext.schain) nodes, privacy enforcement rules (ext.prebid. enforcement), and Prebid Server Price Floors (ext.prebid.floors).
  • Impression-Level Stored Request (configId): Maps 1:1 to a discrete mobile placement (for example, ios_home_feed_native_300x250 or android_rewarded_video_interstitial). It contains the imp[].ext.prebid.bidder dictionary specifying every demand partner's placement, publisher, or tag identifier, along with format constraints (banner, video, or native).

During auction resolution, Prebid Server performs a deep RFC 7396 JSON Merge Patch between the stored impression template and the dynamic runtime telemetry transmitted by the device. Runtime device parameters, such as screen dimensions (device.w, device.h), pixel ratio (device.pxratio), operating system version (device.osv), cellular carrier (device.carrier), and advertising identifiers (device.ifa), overwrite or append to the static template. Below is a production representation of the lightweight payload emitted by the Prebid Mobile SDK alongside the resolved server-side imp template inside Prebid Server:

{
  "id": "8f7b9c12-4a3e-4d9a-b812-09c41f7e5501",
  "imp": [
    {
      "id": "imp_feed_01",
      "banner": {
        "format": [{ "w": 300, "h": 250 }]
      },
      "ext": {
        "prebid": {
          "storedrequest": {
            "id": "sb_android_inline_300x250_v4"
          },
          "floors": {
            "floorMin": 1.25,
            "floorMinCur": "USD"
          }
        }
      }
    }
  ],
  "app": {
    "bundle": "com.publisher.newsreader",
    "ver": "8.4.2",
    "publisher": { "id": "pub_skyboosts_9941" }
  },
  "ext": {
    "prebid": {
      "storedrequest": { "id": "pub_skyboosts_9941" },
      "cache": { "bids": {}, "vastxml": {} },
      "targeting": {
        "pricegranularity": "dense",
        "includewinners": true,
        "includebidderkeys": false
      }
    }
  }
}

Decoupling bidder topology from the client binary solves one of the most persistent operational bottlenecks in mobile AdOps: release cycle inertia. Because Apple App Store and Google Play Store review cycles, staged rollouts, and user update adoption curves routinely span 14 to 30 days, publishers relying on client-side mediation adapters cannot rapidly adjust floor elasticity or onboard new demand seats during seasonal Q4 CPM spikes. By routing placements through Prebid Server Config ID mappings and our comprehensive in-app bidding guide best practices, AdOps teams can activate new S2S demand partners, modify Prebid Server Price Floors rules by geography or device class, and adjust QPS throttling in real time from the server side.

Furthermore, Prebid Server executes ext.prebid.cache operations automatically before returning the auction response to the device. When a participating SSP responds with an winning OpenRTB bid (seatbid[].bid[]), Prebid Server serializes the bid object (or VAST XML payload for video) into Prebid Cache, assigns a unique UUID (hb_cache_id), and returns quantized key-value targeting pairs (hb_pb, hb_size, hb_cache_id, hb_format) to the Prebid Mobile SDK within a strict 600 to 1000 millisecond auction window.

Integrating with Google Mobile Ads (Legacy 25.5.0 vs. GMA Next-Gen SDK 1.0+)

For the vast majority of enterprise publishers, Google Ad Manager (GAM 360) serves as the primary decisioning engine where client-side Prebid Mobile bids compete directly against AdX, Open Bidding, and direct-sold sponsorship line items. On Android, however, the underlying Google Mobile Ads architecture has undergone a major structural overhaul between the legacy com.google.android.gms:play-services-ads library (spanning versions 23.x through 25.5.0) and the GMA Next-Gen SDK (com.google.android.libraries.ads.mobile.sdk:ads-mobile-sdk v1.0+).

In legacy GMA SDK implementations (25.5.0 and earlier), core initialization routines (MobileAds.initialize()) and ad loader constructors relied heavily on synchronous IPC calls to Google Play Services on the Android main UI thread (Looper.getMainLooper()). When an application combined Prebid Mobile's fetchDemand callback with legacy AdManagerAdView.loadAd() execution on the main thread, WebView instantiation and synchronous class-loading spikes regularly exceeded Android's 5-second input dispatch threshold, triggering ANR events that degraded Google Play Vitals scores and suppressed organic store rankings.

The GMA Next-Gen SDK 1.0+ resolves this bottleneck by moving initialization, ad request serialization, and WebView preparation onto background thread pools while exposing a clean, asynchronous API built for Kotlin coroutines. When executing a Prebid Mobile and GMA SDK integration using the GMA Next-Gen SDK, engineering teams should wrap Prebid Mobile's demand-fetching phase inside a coroutine suspendCancellableCoroutine block so that both the S2S OpenRTB auction and the subsequent GAM ad request run off the main thread without blocking frame rendering:

package com.skyboosts.monetization.banner

import android.os.Bundle
import com.google.android.libraries.ads.mobile.sdk.banner.AdSize
import com.google.android.libraries.ads.mobile.sdk.banner.BannerAd
import com.google.android.libraries.ads.mobile.sdk.banner.BannerAdRequest
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import org.prebid.mobile.BannerAdUnit
import org.prebid.mobile.ResultCode
import kotlin.coroutines.resume

class NextGenPrebidBannerController(
    private val scope: CoroutineScope
) {
    fun loadHybridBanner(
        adUnitId: String,
        prebidConfigId: String,
        onAdLoaded: (BannerAd) -> Unit
    ) {
        scope.launch(Dispatchers.IO) {
            val prebidUnit = BannerAdUnit(prebidConfigId, 300, 250).apply {
                setAutoRefreshInterval(0) // Managed externally by controller
            }

            val targetingBundle = fetchPrebidTargeting(prebidUnit)

            val gamRequest = BannerAdRequest.Builder(
                adUnitId,
                AdSize.MEDIUM_RECTANGLE
            ).apply {
                for (key in targetingBundle.keySet()) {
                    targetingBundle.getString(key)?.let { value ->
                        putCustomTargeting(key, value)
                    }
                }
            }.build()

            BannerAd.load(
                gamRequest,
                object : BannerAd.BannerAdLoadCallback() {
                    override fun onAdLoaded(ad: BannerAd) {
                        onAdLoaded(ad)
                    }
                }
            )
        }
    }

    private suspend fun fetchPrebidTargeting(
        adUnit: BannerAdUnit
    ): Bundle = suspendCancellableCoroutine { continuation ->
        val extras = Bundle()
        adUnit.fetchDemand(extras) { resultCode: ResultCode ->
            if (continuation.isActive) {
                continuation.resume(extras)
            }
        }
    }
}

Architecturally, this Original API integration pattern preserves holistic unified auction competition inside GAM 360. Once fetchDemand populates the targeting bundle (or directly mutates the AdManagerAdRequest.Builder on legacy GMA 25.5.0), the request hits GAM with dense price granularity keys (hb_pb=3.45, hb_cache_id=a91c..., hb_size=300x250). Inside GAM, Price Priority (Type 12) line items configured for Prebid Server compete in real time against Google AdX and server-to-server Open Bidding partners on a net CPM basis.

When optimizing in-app bidding mediation, engineering teams must enforce two strict synchronization rules between Prebid Mobile and the GMA SDK:

  1. Disable Dual Auto-Refresh: Never enable auto-refresh simultaneously inside GAM's UI and inside Prebid Mobile (setAutoRefreshInterval). If GAM refreshes the ad slot without invoking fetchDemand first, the stale hb_cache_id from the prior impression is re-sent, causing blank creatives when Prebid Cache TTLs expire or triggering duplicate impression discrepancies. Always disable GAM-side refresh and drive the refresh lifecycle deterministically from the application's visibility state controller.
  2. Calibrate Client vs. Server Timeouts: Set the Prebid Server stored request tmax roughly 150 to 200 milliseconds shorter than the client-side Prebid.setTimeoutMillis() threshold (for example, 800ms server tmax and 1000ms client timeout). This margin accommodates cellular transit latency so that valid Prebid Server responses are not discarded by the client SDK right before the GAM request fires.

Universal Creative Rendering When GAM Is Not the Primary Ad Server

While GAM 360 remains the predominant primary ad server for large publishers, many gaming, utility, and content applications operate either with a custom in-house ad server, an alternative mediation layer, or in a standalone "No Ad Server" topology where Prebid Server acts as the sole auction decisioning engine. Furthermore, even when GAM 360 is used, rendering standard HTML wrappers inside a WebView for in-feed native placements introduces scroll-jank and layout shifts. To address both scenarios, Prebid Mobile provides two distinct rendering pipelines: the Original API (relying on Prebid Universal Creative inside GAM WebViews) and the Rendering API (combined with native asset deserialization).

In the Original API flow with GAM, winning display and video bids are rendered via a lightweight HTML/JavaScript snippet inside the GAM creative template that loads uc.js (Prebid Universal Creative), retrieves the cached bid payload from Prebid Cache via hb_cache_id, and writes the adm markup into an iframe or invokes the IMA SDK for video. By contrast, when GAM is not the primary ad server, the Prebid Mobile Rendering API (BannerView, InterstitialAdUnit, and RewardedAdUnit) bypasses external ad server WebViews entirely. The SDK parses the OpenRTB seatbid[].bid[] response directly on the device, extracts the winning adm, and instantiates its own MRAID 3.0 compliant WebView or native VAST 4.3 video player with built-in end-card support.

For feed-based placements (RecyclerView on Android or UICollectionView / LazyVStack on iOS), Custom Native Rendering delivers the highest user engagement and eCPM yield. Instead of rendering an isolated HTML banner, Prebid Mobile's NativeAdUnit constructs an OpenRTB Dynamic Native Ads API v1.2 request object specifying required and optional structural assets:

val nativeAdUnit = NativeAdUnit(prebidNativeConfigId).apply {
    setContextType(NativeAdUnit.CONTEXT_TYPE.SOCIAL_CENTRIC)
    setPlacementType(NativeAdUnit.PLACEMENTTYPE.CONTENT_FEED)

    val title = NativeTitleAsset().apply {
        setLength(90)
        isRequired = true
    }
    val icon = NativeImageAsset(20, 20, 20, 20).apply {
        imageType = NativeImageAsset.IMAGE_TYPE.ICON
        isRequired = true
    }
    val mainImage = NativeImageAsset(800, 418, 1200, 627).apply {
        imageType = NativeImageAsset.IMAGE_TYPE.MAIN
        isRequired = true
    }
    val cta = NativeDataAsset().apply {
        dataType = NativeDataAsset.DATA_TYPE.CTATEXT
        isRequired = true
    }
    val sponsored = NativeDataAsset().apply {
        dataType = NativeDataAsset.DATA_TYPE.SPONSORED
        isRequired = true
    }

    addAsset(title)
    addAsset(icon)
    addAsset(mainImage)
    addAsset(cta)
    addAsset(sponsored)

    val methods = arrayListOf(
        NativeEventTracker.EVENT_TRACKING_METHOD.IMAGE,
        NativeEventTracker.EVENT_TRACKING_METHOD.JS
    )
    addEventTracker(
        NativeEventTracker(NativeEventTracker.EVENT_TYPE.IMPRESSION, methods)
    )
    addEventTracker(
        NativeEventTracker(NativeEventTracker.EVENT_TYPE.VIEWABLE_MRC50, methods)
    )
}

When a demand partner returns a winning OpenRTB Native 1.2 JSON response, the payload is cached and linked via hb_cache_id_local. Whether the publisher renders the native placement immediately after a standalone fetchDemand call or after a GAM custom native template callback (NativeCustomFormatAd), the application invokes PrebidNativeAd.create(cacheId, listener) to deserialize the cached JSON into typed getters (nativeAd.title, nativeAd.iconUrl, nativeAd.imageUrl, nativeAd.callToAction, nativeAd.sponsoredBy).

The most critical engineering step in custom native rendering is view registration and lifecycle management. Because there is no WebView executing automatic JavaScript impression pixels, the host application must bind the inflated native container view and its clickable subviews directly to the PrebidNativeAd instance via nativeAd.registerView(containerView, listOf(titleView, ctaButton, mainImageView), listener). Under the hood, registerView attaches an OnPreDrawListener and visibility polling mechanism that fires the IMPRESSION event tracker upon 1-pixel render and fires the VIEWABLE_MRC50 beacon strictly after 50% of the container's pixels remain continuously visible in the viewport for 1,000 milliseconds. When a RecyclerView.ViewHolder is recycled off-screen, engineers must clean up old view references so viewability state machines do not leak memory or misfire beacons across recycled cells.

Passing App-Level First-Party Data, Geo Coordinates, and OM SDK v1.5 Signals

Maximizing bid density and clearing prices in server-to-server mobile auctions depends directly on the fidelity of the bidstream signals passed from the Prebid Mobile SDK to Prebid Server. With Apple's AppTrackingTransparency (ATT) framework limiting IDFA availability on iOS to roughly 20% to 25% of global impressions and Android privacy controls tightening adid access, tier-1 DSPs heavily discount unenriched S2S bid requests unless contextual First-Party Data (FPD), precise location telemetry (where consented), and verified viewability signals are present.

First, publishers should populate deterministic First-Party Data using Prebid Mobile's TargetingParams API, which maps directly into OpenRTB 2.6 app.ext.data, user.ext.data, and imp[].ext.data structures. Rather than passing arbitrary key-value strings that DSPs cannot parse, engineering teams should classify inventory using standardized IAB Tech Lab Content Taxonomy v3.0 codes (app.content.cat, cattax: 6) alongside publisher-declared audience segments:

  • Application Context (TargetingParams.addExtData): Pass content vertical, article or screen category, language, and session depth into app.ext.data.
  • Publisher-Provided Identifiers (TargetingParams.setExternalUserIds): Pass hashed or first-party session identifiers (eids) alongside Google Pair or Publisher Provided Identifiers (PPID) to support frequency capping and audience matching in IDFA-less environments.

Second, location signals (device.geo.lat, device.geo.lon, device.geo.accuracy, and device.geo.type = 1 for GPS/Location Services) drive significant CPM lift from retail, automotive, and QSR buyers, provided regulatory consent is properly verified. Prebid Mobile automatically monitors platform storage (SharedPreferences on Android and NSUserDefaults on iOS) for IAB TCF v2.2 (IABTCF_TCString, IABTCF_gdprApplies) and IAB Global Privacy Platform (IABGPP_HDR_GppString, IABGPP_GppSID) strings. When calling PrebidMobile.setShareGeoLocation(true), the SDK attaches high-precision GPS coordinates from the OS location manager only if the application holds runtime OS location permissions (ACCESS_FINE_LOCATION or CLAuthorizationStatusAuthorizedWhenInUse) and the user's GPP/TCF consent string permits geolocation processing on Prebid Server.

Third, in-app S2S inventory suffers severe bid shading if the Open Measurement SDK (OM SDK v1.5) signals are missing or malformed. DSPs rely on IAB Tech Lab's OM SDK to execute third-party verification scripts (such as HUMAN, Pixalate, DoubleVerify, and IAS) inside native mobile environments without requiring proprietary vendor SDKs. In Prebid Mobile, OM SDK v1.5 support is baked into the rendering core, which populates two mandatory OpenRTB fields in every bid request:

  1. source.ext.omidpn and source.ext.omidpv: Identifies the Open Measurement partner name ("Prebid") and the active OM SDK version string ("1.5.x").
  2. imp[].banner.api and imp[].video.api: Appends 7 (the OpenRTB API framework code for OMID-1) alongside 3, 5, and 6 (MRAID 1.0, 2.0, and 3.0).

When rendering custom UI overlays atop video or interstitial placements, such as custom mute buttons, progress bars, or skip countdown badges, mobile engineers must register those views as friendly obstructions (addFriendlyObstruction). If an application places an unregistered transparent View or UIView overlay above the ad container, the OM SDK geometry calculation flags the overlapping bounding box as an obstruction, reducing the reported on-screen viewability percentage and causing MRC viewability rates to plummet below the 70% threshold required by premium programmatic guaranteed and private marketplace deals.

To achieve sustained yield elevation across iOS and Android applications, treat your Prebid Mobile integration as a unified telemetry pipeline: decouple bidder configurations into Prebid Server Config ID templates, migrate Android ad loading to asynchronous GMA Next-Gen SDK coroutines, bind custom native layouts directly to OpenRTB 1.2 asset trackers, and audit every outgoing /openrtb2/auction payload for complete OM SDK v1.5, GPP, and First-Party Data parameters.

Next step

Put it to work.

Every pattern in this article runs on our unified SSP and monetization platform: GAM and MCM management, Prebid client and server-side, and CTV SSAI.

Net-30 / Net-60 terms · 100% brand-safe demand