Mobile apps present a unique challenge for rich media advertising. Unlike web browsers, where ads run in a relatively standardized environment with access to the DOM and JavaScript APIs, mobile app ads live inside a WebView controlled by the app's ad SDK. Without a common interface standard, every ad SDK implemented ad rendering differently, forcing creative developers to build separate versions for each SDK. MRAID (Mobile Rich Media Ad Interface Definitions) solves this by defining a standardized JavaScript API that ad creatives can use to interact with the host app's SDK.

What Is MRAID?

MRAID is an IAB Tech Lab specification that defines a JavaScript bridge between rich media ad creatives and the mobile app SDK that renders them. When an MRAID-compliant ad is loaded inside an app, the SDK injects a JavaScript API into the WebView. The ad creative can then call MRAID methods to request actions like expanding to fullscreen, resizing, opening a URL, or detecting viewability—all without needing to know which SDK is hosting it.

The Problem MRAID Solves

Before MRAID, a creative agency building an expandable banner ad for mobile apps had to:

MRAID eliminates this fragmentation by providing a single, universal API that all compliant SDKs support.

Version History

VersionYearKey Additions
MRAID 1.02011Initial specification. Basic expand, close, resize, and open actions. State management (loading, default, expanded, hidden).
MRAID 2.02014Two-part expand (expand to custom size). SetOrientationProperties. Supports custom close regions. Screen size reporting.
MRAID 3.02018Native-style ad support. Viewability measurement API (exposureChange). Improved audio state tracking. Enhanced error handling. getLocation method.

The MRAID JavaScript API

MRAID defines a JavaScript object (mraid) that the host SDK injects into the ad's WebView. The ad creative checks for MRAID readiness, registers event listeners, and then calls MRAID methods as needed.

Initialization Pattern

// Standard MRAID initialization pattern
(function() {
  if (typeof mraid === 'undefined') {
    // MRAID not available - fallback to non-MRAID behavior
    console.log('MRAID not available');
    return;
  }

  // Wait for MRAID to be ready
  mraid.addEventListener('ready', function() {
    console.log('MRAID is ready, version:', mraid.getVersion());
    console.log('Current state:', mraid.getState());
    console.log('Screen size:', JSON.stringify(mraid.getScreenSize()));

    // Set up event listeners
    mraid.addEventListener('stateChange', onStateChange);
    mraid.addEventListener('viewableChange', onViewableChange);
    mraid.addEventListener('sizeChange', onSizeChange);

    // Start the ad
    initAd();
  });

  function onStateChange(state) {
    console.log('State changed to:', state);
    if (state === 'expanded') {
      // Load expanded creative
    } else if (state === 'default') {
      // Return to default view
    }
  }

  function onViewableChange(viewable) {
    console.log('Viewable:', viewable);
    if (viewable) {
      // Start animations, video, etc.
    } else {
      // Pause animations, mute audio
    }
  }
})();

Core Methods

MethodDescription
mraid.getVersion()Returns the MRAID version supported by the SDK (e.g., "3.0")
mraid.getState()Returns current ad state: "loading", "default", "expanded", "resized", or "hidden"
mraid.expand([url])Expands the ad to fullscreen or a larger overlay. Optionally loads a new URL in the expanded view.
mraid.close()Closes the expanded/resized ad and returns to the default state or removes the ad entirely.
mraid.resize(width, height)Resizes the ad container to the specified dimensions (MRAID 2.0+).
mraid.open(url)Opens a URL in the device's browser or an in-app browser.
mraid.getScreenSize()Returns the screen dimensions in density-independent pixels.
mraid.getMaxSize()Returns the maximum size the ad can expand to.
mraid.getDefaultPosition()Returns the default position and size of the ad container.
mraid.getCurrentPosition()Returns the current position and size (may differ if resized).
mraid.isViewable()Returns whether the ad is currently viewable on screen.
mraid.setOrientationProperties(...)Controls allowed device orientations during expanded state.
mraid.playVideo(url)Opens the device's native video player with the specified URL.
mraid.storePicture(url)Saves an image to the device's photo gallery (requires user permission).
mraid.supports(feature)Checks if the SDK supports a specific feature (sms, tel, calendar, storePicture, inlineVideo).

MRAID 3.0: Viewability and Native-Style Ads

Exposure Change Events

MRAID 3.0 introduced the exposureChange event, which provides granular viewability data to the ad creative. Unlike the simple boolean isViewable() method, exposureChange reports the exact percentage of the ad that is visible, along with information about which portions are obscured:

mraid.addEventListener('exposureChange', function(exposure) {
  console.log('Exposed percentage:', exposure.exposedPercentage);
  console.log('Visible viewport:', JSON.stringify(exposure.visibleRectangle));

  // exposure.exposedPercentage: 0-100
  // exposure.visibleRectangle: {x, y, width, height}
  // exposure.reasons: array of reasons for partial visibility
  //   - "adFullyOccluded" (another view covers the ad)
  //   - "adPartiallyOccluded"
  //   - "screenOff" (device screen is off)
  //   - "minimized" (app is backgrounded)
  //   - "back" (ad is behind another screen)

  if (exposure.exposedPercentage >= 50) {
    // Ad meets standard viewability criteria
    startTracking();
  }
});

Audio State Tracking

MRAID 3.0 added the audioVolumeChange event, enabling video ads to respond to audio state changes. This is particularly important for autoplay video ads, which should mute when the device is in silent mode:

mraid.addEventListener('audioVolumeChange', function(volume) {
  // volume: 0 (muted) to 1.0 (full volume)
  // -1 indicates volume could not be determined
  if (volume === 0) {
    videoElement.muted = true;
    showCaptions(true);
  } else {
    videoElement.muted = false;
    videoElement.volume = volume;
    showCaptions(false);
  }
});

Native-Style Ads

MRAID 3.0 introduced support for native-style ads—ads that render using the app's native UI components rather than a WebView. This enables ad formats that blend seamlessly with the app's content, improving user experience and engagement. The SDK provides the ad creative with content data (headline, body text, images, CTA) through the MRAID API, and the creative can render this content using platform-native UI elements.

State Machine

MRAID defines a clear state machine that governs the ad's lifecycle. Understanding state transitions is critical for both creative developers and SDK implementors:

StateDescriptionTransitions To
loadingThe ad is being loaded into the WebViewdefault
defaultThe ad is displayed at its original sizeexpanded, resized, hidden
expandedThe ad has expanded to a larger overlaydefault (on close)
resizedThe ad has been resized to custom dimensionsdefault (on close)
hiddenThe ad is not visible (e.g., interstitial dismissed)default

Creatives must always check their current state before calling action methods. Calling expand() from a non-default state will throw an error. Similarly, calling close() from the default state will remove the ad entirely, while calling it from expanded or resized state will return to default.

Implementation Guide for SDK Developers

WebView Setup

The SDK must inject the MRAID JavaScript bridge into the WebView before the ad creative's JavaScript executes. This is typically done by loading the MRAID library script before the ad's HTML content:

// Android (Kotlin) - Injecting MRAID into WebView
webView.addJavascriptInterface(
    MraidBridge(this), "mraid"
)

// Load MRAID library first, then the ad creative
webView.loadUrl("javascript:mraidInit();")

class MraidBridge(private val adController: AdController) {
    @JavascriptInterface
    fun getVersion(): String = "3.0"

    @JavascriptInterface
    fun getState(): String = adController.currentState.name

    @JavascriptInterface
    fun expand(url: String?) {
        adController.expandAd(url)
    }

    @JavascriptInterface
    fun close() {
        adController.closeAd()
    }

    @JavascriptInterface
    fun isViewable(): Boolean {
        return adController.checkViewability()
    }
}

Viewability Calculation

Implementing accurate viewability measurement is one of the most complex aspects of MRAID SDK development. The SDK must continuously monitor:

On Android, this requires using View.getLocationOnScreen(), View.getGlobalVisibleRect(), and checking the view hierarchy for overlapping views. On iOS, the equivalent functionality uses UIView.convertRect:toView: and the layer presentation tree.

Error Handling

The SDK should fire the error event when MRAID operations fail, providing both a human-readable message and an error code:

// MRAID error codes
const MRAID_ERROR_CODES = {
  UNKNOWN: 1,
  UNSUPPORTED: 2,
  NATIVE: 3,
  AD: 4,
  TRANSPORT: 5
};

// Fire error event
function fireError(message, code) {
  webView.evaluateJavascript(
    "window.dispatchEvent(new CustomEvent('mraid:error', " +
    "{detail: {message: '$message', action: '$code'}}))"
  );
}

Testing and Validation

The IAB Tech Lab provides MRAID testing tools and reference implementations to help both creative developers and SDK implementors validate their work:

Challenges and Considerations

MRAID in the Broader Standards Ecosystem

MRAID works alongside other IAB standards in the mobile advertising stack. In a typical mobile ad transaction: OpenRTB delivers the bid request and response, the creative is served as an MRAID-compliant HTML page rendered in a WebView, viewability is measured through both MRAID's built-in viewability API and the OM SDK for standardized third-party verification, and the publisher's app-ads.txt file authorizes the selling entity. Understanding how MRAID fits into this ecosystem helps developers build ad experiences that work reliably across the full programmatic supply chain.