Skip to content

Examples

alxspiker edited this page Jul 31, 2025 · 2 revisions

πŸ’» Pi Network SDK Examples

Production-ready code samples for Pi Network integration

Modern examples featuring hybrid app architecture and Pi Browser detection

πŸ”„ What's New & Improved

🎯 All examples now include hybrid app support with smart Pi Browser detection

✨ Key Improvements:

  • βœ… Smart Detection - Pi Browser detection using Pi.getPiHostAppInfo() with fallbacks
  • βœ… User-Initiated Auth - No more scary popups, authentication only when users choose
  • βœ… Graceful Fallbacks - Professional UI for non-Pi Browser users
  • βœ… Better UX - Seamless experience across all environments

πŸ”— Related: See our Pi Browser Detection Guide for implementation details


πŸ“ Featured Examples

πŸš€ Example πŸ“ Description 🎯 Features πŸ’Ό Use Case
Basic Login & Pay Simple authentication and payments Auth, Payments, Detection Getting started, prototypes
Python Subscriptions Flask backend with hybrid frontend Full-stack, API integration SaaS, subscription services
Full SDK Demo Comprehensive Pi features showcase All SDK methods, best practices Learning, reference implementation

πŸš€ Basic Login & Pay {#basic-login-pay}

🎯 Perfect starting point: Simple authentication and payment integration with hybrid support

πŸ“‹ What This Example Shows:

  • Smart Pi Browser detection before authentication
  • User-initiated login (no scary popups)
  • Graceful fallback UI for regular browsers
  • Simple payment integration

πŸ”„ Before vs After

❌ Old Approach βœ… New Hybrid Approach
Called Pi.authenticate() on page load Detects Pi Browser first, then shows login option
Broke in regular browsers Works everywhere with appropriate UI
Scary authentication popups User-initiated authentication flow

πŸ’» Implementation

Complete Example Code
// app.js - Modern hybrid approach
async function initApp() {
  // 1. Initialize Pi SDK
  Pi.init({ version: "2.0", sandbox: true });
  
  // 2. Detect Pi Browser environment
  const isPiBrowser = await detectPiBrowser();
  
  if (!isPiBrowser) {
    // 3a. Show fallback for regular browsers
    showFallbackUI();
    return;
  }
  
  // 3b. Enable Pi features for Pi Browser users
  enablePiFeatures();
}

function showFallbackUI() {
  document.getElementById('app').innerHTML = `
    <div class="fallback-container">
      <h2>πŸ₯§ Pi Login Available in Pi Browser</h2>
      <p>For full functionality including payments and Pi authentication:</p>
      
      <div class="cta-section">
        <a href="https://pinet.com/YOUR_APP" class="pi-button">
          Open in Pi Browser
        </a>
      </div>
      
      <div class="info-section">
        <h3>What you'll get in Pi Browser:</h3>
        <ul>
          <li>βœ… Secure Pi Network authentication</li>
          <li>βœ… Pi cryptocurrency payments</li>
          <li>βœ… Full app functionality</li>
        </ul>
      </div>
    </div>
  `;
}

function enablePiFeatures() {
  // Show Pi Browser-specific UI
  document.getElementById('login-section').style.display = 'block';
  document.getElementById('login-btn').onclick = handleLogin;
}

async function handleLogin() {
  try {
    const auth = await Pi.authenticate(['payments'], onIncompletePaymentFound);
    console.log('βœ… Authentication successful:', auth);
    
    // Update UI for logged-in user
    document.getElementById('user-info').innerHTML = `
      <h3>Welcome!</h3>
      <p>User ID: ${auth.user.uid}</p>
    `;
    
    // Show payment option
    document.getElementById('payment-section').style.display = 'block';
  } catch (error) {
    console.error('❌ Login failed:', error);
  }
}

async function handlePayment() {
  try {
    const payment = await Pi.createPayment({
      amount: 1.0,
      memo: "Test payment",
      metadata: { example: true }
    }, {
      onReadyForServerApproval: function(paymentId) {
        console.log('Payment ready for approval:', paymentId);
      },
      onReadyForServerCompletion: function(paymentId, txid) {
        console.log('Payment ready for completion:', paymentId, txid);
      },
      onCancel: function(paymentId) {
        console.log('Payment cancelled:', paymentId);
      },
      onError: function(error, payment) {
        console.error('Payment error:', error);
      }
    });
  } catch (error) {
    console.error('❌ Payment failed:', error);
  }
}

function onIncompletePaymentFound(payment) {
  console.log('Found incomplete payment:', payment);
  // Handle incomplete payment logic here
}

// Initialize app when DOM is ready
document.addEventListener('DOMContentLoaded', initApp);

HTML Structure:

<!DOCTYPE html>
<html>
<head>
    <title>Pi Network Example - Login & Pay</title>
    <script src="https://sdk.minepi.com/pi-sdk.js"></script>
</head>
<body>
    <div id="app">
        <div id="login-section" style="display: none;">
            <button id="login-btn">Login with Pi</button>
        </div>
        
        <div id="user-info" style="display: none;"></div>
        
        <div id="payment-section" style="display: none;">
            <button onclick="handlePayment()">Make Payment (1 Pi)</button>
        </div>
    </div>
    
    <script src="app.js"></script>
</body>
</html>
} }

async function detectPiBrowser() { const timeout = new Promise(resolve => setTimeout(() => resolve("timeout"), 3000));

try { if (window?.Pi?.getPiHostAppInfo) { const result = await Promise.race([window.Pi.getPiHostAppInfo(), timeout]); return result?.hostApp === "pi-browser"; } } catch (e) { console.warn("Pi SDK detection failed", e); }

const ua = navigator?.userAgent?.toLowerCase() || ""; return ua.includes("pibrowser") || document.referrer.includes("minepi.com"); }

function onIncompletePaymentFound(payment) { console.log("Found incomplete payment:", payment); }

// Initialize app document.addEventListener('DOMContentLoaded', initApp);


### 2. Python Login Pay Subscriptions

**Before:** Auto-login on page load
**After:** Detects Pi Browser, shows login button for Pi users, provides fallback message for regular browsers

```javascript
// Updated python-login-pay-subscriptions/static/app.js
class PiApp {
  constructor() {
    this.user = null;
    this.init();
  }

  async init() {
    const isPiBrowser = await this.detectPiBrowser();
    
    if (!isPiBrowser) {
      this.showFallbackUI();
      return;
    }

    this.setupPiUI();
  }

  showFallbackUI() {
    document.body.innerHTML = `
      <div class="container">
        <h1>Pi Subscription Service</h1>
        <div class="fallback-message">
          <h2>Available in Pi Browser</h2>
          <p>This subscription service requires Pi Browser for secure payments.</p>
          <div class="qr-code">
            <img src="/static/qr-code.png" alt="Scan with Pi Browser" />
            <p>Scan this QR code with Pi Browser</p>
          </div>
          <a href="https://pinet.com/YOUR_APP" class="pi-button">Open in Pi Browser</a>
        </div>
      </div>
    `;
  }

  setupPiUI() {
    document.getElementById('login-btn').style.display = 'block';
    document.getElementById('login-btn').onclick = () => this.handleLogin();
  }

  async handleLogin() {
    try {
      const auth = await Pi.authenticate(['payments'], (payment) => {
        console.log("Incomplete payment found:", payment);
      });
      
      this.user = auth.user;
      this.updateUIForLoggedInUser();
    } catch (error) {
      console.error('Authentication failed:', error);
    }
  }

  async detectPiBrowser() {
    const timeout = new Promise(resolve => 
      setTimeout(() => resolve("timeout"), 3000)
    );

    try {
      if (window?.Pi?.getPiHostAppInfo) {
        const result = await Promise.race([window.Pi.getPiHostAppInfo(), timeout]);
        return result?.hostApp === "pi-browser";
      }
    } catch (e) {
      console.warn("Pi SDK detection failed", e);
    }

    const ua = navigator?.userAgent?.toLowerCase() || "";
    return ua.includes("pibrowser") || document.referrer.includes("minepi.com");
  }

  updateUIForLoggedInUser() {
    document.getElementById('user-section').innerHTML = `
      <h2>Welcome, ${this.user.uid}!</h2>
      <button onclick="app.subscribe()">Subscribe for 5Ο€</button>
    `;
  }

  async subscribe() {
    const payment = await Pi.createPayment({
      amount: 5,
      memo: "Monthly subscription",
      metadata: { type: "subscription" }
    }, {
      onReadyForServerApproval: (paymentId) => {
        // Send to Flask backend
        fetch('/approve_payment', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ paymentId })
        });
      },
      onReadyForServerCompletion: (paymentId, txid) => {
        fetch('/complete_payment', {
          method: 'POST', 
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ paymentId, txid })
        });
      }
    });
  }
}

const app = new PiApp();

3. Pi Network SDK Example

Before: All SDK functions available without detection After: Detects Pi Browser, hides SDK features in regular browsers, shows clear warning message

<!-- Updated Pi-Network-SDK-Example/index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Pi Network SDK Example</title>
    <script src="https://sdk.minepi.com/pi-sdk.js"></script>
</head>
<body>
    <div id="app">
        <h1>Pi Network SDK Example</h1>
        <div id="detection-status">Detecting Pi Browser...</div>
        <div id="pi-features" style="display: none;">
            <button id="auth-btn">Authenticate</button>
            <button id="payment-btn" style="display: none;">Make Payment</button>
            <div id="user-info"></div>
        </div>
        <div id="fallback-ui" style="display: none;">
            <h2>Pi Network Features</h2>
            <p>This example showcases Pi Network SDK features that are available in Pi Browser.</p>
            <div class="feature-list">
                <h3>Available Features:</h3>
                <ul>
                    <li>βœ… User Authentication</li>
                    <li>βœ… Pi Payments</li>
                    <li>βœ… App Info Access</li>
                    <li>βœ… Conversation API</li>
                </ul>
            </div>
            <div class="cta">
                <p><strong>To try these features:</strong></p>
                <a href="https://pinet.com/YOUR_APP" class="pi-button">Open in Pi Browser</a>
            </div>
        </div>
    </div>

    <script>
        Pi.init({ version: "2.0", sandbox: true });

        async function initializeApp() {
            const isPiBrowser = await detectPiBrowser();
            
            document.getElementById('detection-status').textContent = 
                isPiBrowser ? 'βœ… Pi Browser Detected' : '❌ Regular Browser Detected';

            if (!isPiBrowser) {
                document.getElementById('fallback-ui').style.display = 'block';
                return;
            }

            // Show Pi features
            document.getElementById('pi-features').style.display = 'block';
            setupPiFeatures();
        }

        function setupPiFeatures() {
            document.getElementById('auth-btn').onclick = async () => {
                try {
                    const auth = await Pi.authenticate(['payments'], onIncompletePaymentFound);
                    document.getElementById('user-info').innerHTML = `
                        <h3>Authenticated User:</h3>
                        <p>UID: ${auth.user.uid}</p>
                    `;
                    document.getElementById('payment-btn').style.display = 'block';
                } catch (error) {
                    console.error('Authentication failed:', error);
                }
            };

            document.getElementById('payment-btn').onclick = async () => {
                const payment = await Pi.createPayment({
                    amount: 1,
                    memo: "Test payment",
                    metadata: { example: true }
                }, {
                    onReadyForServerApproval: (paymentId) => {
                        console.log('Payment ready for approval:', paymentId);
                    },
                    onReadyForServerCompletion: (paymentId, txid) => {
                        console.log('Payment completed:', paymentId, txid);
                    }
                });
            };
        }

        async function detectPiBrowser() {
            const timeout = new Promise(resolve => 
                setTimeout(() => resolve("timeout"), 3000)
            );

            try {
                if (window?.Pi?.getPiHostAppInfo) {
                    const result = await Promise.race([window.Pi.getPiHostAppInfo(), timeout]);
                    return result?.hostApp === "pi-browser";
                }
            } catch (e) {
                console.warn("Pi SDK detection failed", e);
            }

            const ua = navigator?.userAgent?.toLowerCase() || "";
            return ua.includes("pibrowser") || document.referrer.includes("minepi.com");
        }

        function onIncompletePaymentFound(payment) {
            console.log("Found incomplete payment:", payment);
        }

        // Initialize app when DOM is ready
        document.addEventListener('DOMContentLoaded', initializeApp);
    </script>

    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        .fallback-ui { background: #f5f5f5; padding: 20px; border-radius: 8px; }
        .feature-list { margin: 20px 0; }
        .cta { margin-top: 20px; }
        .pi-button { 
            display: inline-block; 
            background: #7b2cbf; 
            color: white; 
            padding: 12px 24px; 
            text-decoration: none; 
            border-radius: 6px; 
            font-weight: bold;
        }
        #detection-status { 
            padding: 10px; 
            margin: 10px 0; 
            border-radius: 4px; 
            background: #e3f2fd; 
        }
    </style>
</body>
</html>

πŸ› οΈ Utility Functions

Pi Browser Detection Utility

// utils/pi-browser-detection.js
class PiBrowserDetection {
  // Async function to detect Pi Browser
  static async detectPiBrowser() {
    const timeout = new Promise(resolve => 
      setTimeout(() => resolve("timeout"), 3000)
    );

    try {
      if (window?.Pi?.getPiHostAppInfo) {
        const result = await Promise.race([window.Pi.getPiHostAppInfo(), timeout]);
        return result?.hostApp === "pi-browser";
      }
    } catch (e) {
      console.warn("❌ Pi SDK detection failed", e);
    }

    // Fallback: User-Agent or Referrer
    const ua = navigator?.userAgent?.toLowerCase() || "";
    return ua.includes("pibrowser") || document.referrer.includes("minepi.com");
  }

  // Helper to create fallback UI elements
  static createFallbackUI(appLink = "https://pinet.com/YOUR_APP") {
    return `
      <div class="pi-fallback">
        <h3>Pi Features Available in Pi Browser</h3>
        <p>For full functionality, open this app in Pi Browser:</p>
        <a href="${appLink}" class="pi-button">Open in Pi Browser</a>
      </div>
    `;
  }

  // React-style hook simulation for vanilla JS
  static createHook() {
    let isInPiBrowser = null;
    let listeners = [];

    const notify = () => listeners.forEach(fn => fn(isInPiBrowser));
    
    const detect = async () => {
      isInPiBrowser = await this.detectPiBrowser();
      notify();
    };

    const subscribe = (callback) => {
      listeners.push(callback);
      if (isInPiBrowser !== null) callback(isInPiBrowser);
      return () => listeners = listeners.filter(fn => fn !== callback);
    };

    detect();
    return { subscribe, getCurrentValue: () => isInPiBrowser };
  }
}

// Export for use in other files
window.PiBrowserDetection = PiBrowserDetection;

🎯 Benefits

  • βœ… Hybrid App Support - Works in both Web2 and Web3 environments
  • βœ… Clean UX - No confusing popups in regular browsers
  • βœ… Proper Authentication Flow - User-initiated login only
  • βœ… Fallback UI - Clear messaging for non-Pi Browser users
  • βœ… Production Ready - Includes proper cleanup and error handling

πŸš€ Usage Pattern

// 1. Detect Pi Browser
const isPiBrowser = await detectPiBrowser();

// 2. Show appropriate UI
if (!isPiBrowser) {
    // Show fallback UI
    showFallbackMessage();
    return;
}

// 3. Only then enable Pi features
enablePiFeatures();

This pattern ensures your Pi Network apps work smoothly across all environments while providing the best possible experience for Pi Browser users.

See Also

🧭 Pi Developer Navigation

πŸš€ Getting Started


πŸ“– Core References


πŸ› οΈ Implementation Guides


🌟 Platform Features


βš™οΈ Environment & Deployment


πŸ“œ Legal & Compliance


πŸ“‘ Resources & Whitepapers


πŸ’‘ Need help? Join our Discord community!

Clone this wiki locally