Pi Network Ads

The Pi Network JS SDK provides a module for integrating native ads into your Pi app via the window.Pi.Ads namespace. This API enables you to show Pi-managed ad units in your web frontend using simple, promise-based methods. For a detailed explanation, please refer to the platform guide: Ads

This guide demonstrates how to integrate the Pi SDK into many application frameworks. This example shows how to initialize the Pi SDK, authenticate a Pioneer, and create a payment request inside a Pi app.

The pi-sdk-js package is part of the “Ten Minutes to Transactions” effort described in this video.

If you, or your GenAI agent, are planning to use the Pi SDK modules in this documentation for your app, it is highly suggested that you use this package rather than implement transaction processing by hand with the core Pi SDK. The three way handshake between client, server, and the Pi servers required is provded for you.

Note: Pi SDK authentication and payment features require the application to run inside the Pi Browser.


Purpose

  • Enable apps to programmatically show rewarded or interstitial ads in Pi Browser.
  • Maintain compliance with Pi Network ad policies.
  • Monetize or reward users with wallet-connected incentives.

Available Ad Types

  • interstitial: Full-screen ads, typically shown between user actions (e.g., between game levels).
  • rewarded: Ads that, once watched, allow the app to reward the user (e.g., unlock content, give discounts).

Overview

  • Purpose: Manage/show platform advertisement units.
  • Structure:

window.Pi.Ads.isAdReady(type)
window.Pi.Ads.requestAd(type)
window.Pi.Ads.showAd(type)
  • type: 'interstitial' 'rewarded'
  • All methods are Promise-based.

window.Pi.Ads Methods

.isAdReady(type)

  • Purpose: Checks if an ad unit of the specified type is available to show.
  • Signature:

Pi.Ads.isAdReady('interstitial' | 'rewarded') : Promise<result>
  • Returns: A promise that resolves to true if ad is available, otherwise false.

.requestAd(type)

  • Purpose: Requests an ad of the given type from Pi Network. May cache/preload an ad for fastest showing.
  • Signature:

Pi.Ads.requestAd('interstitial' | 'rewarded') : Promise<result>
  • Returns: A promise resolved when the ad is preloaded/ready. If an ad is already ready, resolves immediately. Rejects if not available or request denied.

.showAd(type)

  • Purpose: Shows an ad of the given type. Should be called only if isAdReady(type) returns true.
  • Signature:

Pi.Ads.showAd('interstitial' | 'rewarded') : Promise<result>
  • Returns: A promise resolved when the ad has finished showing, or rejected if unavailable, canceled, or failed.

Typical Usage Pattern

// Example: Show a rewarded ad, then give user a bonus
Pi.Ads.isAdReady('rewarded').then(function(ready) {
  if (ready) {
    Pi.Ads.showAd('rewarded').then(function(result) {
      // Ad finished! Give the user a reward
      grantUserBonus();
    }).catch(function(err) {
      // User canceled, ad failed, or unavailable
      alert('Could not show ad: ' + err.message);
    });
  } else {
    // Ad not ready; maybe preload
    Pi.Ads.requestAd('rewarded');
  }
});

Complete Working Example (Rewarded Ad with Server Verification)

Important: Never grant a reward based on the client-side AD_REWARDED result alone. Always verify the adId server-side via the Pi Platform API. See Common Mistakes.

async function showRewardedAdAndGrantLife(accessToken) {
  if (!window.Pi?.Ads) {
    console.warn('Pi Ads not available in this environment.');
    return;
  }

  try {
    // 1. Check if ad is ready; request one if not
    const readyRes = await window.Pi.Ads.isAdReady('rewarded');
    if (!readyRes.ready) {
      const loadRes = await window.Pi.Ads.requestAd('rewarded');
      if (loadRes.result !== 'AD_LOADED') {
        console.log('No ad available right now.');
        return;
      }
    }

    // 2. Show the ad
    const showRes = await window.Pi.Ads.showAd('rewarded');

    // 3. Check client result — but do NOT grant reward yet
    if (showRes.result !== 'AD_REWARDED' || !showRes.adId) {
      console.log('Ad not completed or no adId returned.');
      return;
    }

    // 4. Verify server-side before granting reward
    //    Include the user's accessToken so your backend can identify them
    const verifyRes = await fetch('/api/ads/reward', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${accessToken}`,  // REQUIRED for user identification
      },
      body: JSON.stringify({ adId: showRes.adId }),
    });
    const data = await verifyRes.json();

    // 5. Only grant reward after server confirms
    if (data.rewarded) {
      grantExtraLife();  // Safe to reward here
    } else {
      console.warn('Reward not confirmed by Pi backend.');
    }
  } catch (err) {
    console.error('Pi Ads error:', err);
  }
}

Backend verification (any server language):

GET https://api.minepi.com/v2/ads_network/status/{adId}
Authorization: Key <YOUR_PI_API_KEY>

Response includes mediator_ack_status. Only grant the reward if its value is "granted":

{
  "identifier": "...",
  "mediator_ack_status": "granted",
  "mediator_granted_at": "2024-01-01T00:00:00Z",
  "mediator_revoked_at": null
}

Interstitial Ad Example

async function showInterstitialBetweenLevels() {
  if (!window.Pi?.Ads) return;

  try {
    const readyRes = await window.Pi.Ads.isAdReady('interstitial');
    if (!readyRes.ready) {
      const loadRes = await window.Pi.Ads.requestAd('interstitial');
      if (loadRes.result !== 'AD_LOADED') return;
    }
    // Interstitials don't require server-side verification — no adId to verify
    await window.Pi.Ads.showAd('interstitial');
  } catch (err) {
    // Interstitial errors are non-critical; continue game flow
    console.warn('Interstitial ad failed:', err);
  }
}

Error Handling

  • All ad methods return Promises; always use .catch to handle errors (ad not ready, request denied, unsupported type).
  • Valid ad types: 'interstitial' and 'rewarded'. Any other string will reject with an error.

Best Practices

  • Always check isAdReady(type) before showing an ad.
  • Use requestAd(type) at app launch to preload ads for lowest latency.
  • Handle edge cases (user cancels ad, ad fails to load) gracefully.
  • Don’t spam ad requests or force user to watch too many ads per session (see Pi Network policy).
  • Only reward users after successful completion of a rewarded ad.
  • Do not attempt to show native ads outside Pi Browser; always feature-detect the available API.