Migration Guide - alxspiker/Pi-Network-Developer-Docs GitHub Wiki

🔄 Migration Guide: Upgrading to Hybrid App Architecture

Transform your existing Pi Network app to work seamlessly across all environments

Step-by-step guide to implementing hybrid Web2/Web3 compatibility

🎯 Why Migrate to Hybrid Architecture?

🚀 Future-proof your Pi Network application with modern hybrid design

Migration Benefits:

  • Enhanced User Experience - No confusing popups in regular browsers
  • Expanded Reach - Works for both Web2 users and Pi Network pioneers
  • Future-Ready Design - Prepared for Pi Network's mainstream adoption
  • Professional UX - Graceful fallbacks with helpful guidance
  • Better Conversion - More users can experience your app

📊 Before vs After Comparison

🔧 Aspect ❌ Legacy Approach ✅ Hybrid Approach
Browser Support Pi Browser only All browsers with smart adaptation
User Experience Broken in regular browsers Graceful fallbacks everywhere
Authentication Scary popups, auto-triggered User-initiated, context-aware
Accessibility Limited to Pi ecosystem Universal accessibility

⚡ Quick Migration Checklist

📋 Essential steps to upgrade your existing Pi Network application

1. Add Pi Browser Detection

Replace immediate SDK calls with browser detection:

// ❌ Before: Immediate authentication
Pi.authenticate(['payments'], callback);

// ✅ After: Detect first, then authenticate
async function init() {
  const isPiBrowser = await detectPiBrowser();
  if (!isPiBrowser) {
    showFallbackUI();
    return;
  }
  // Only show Pi features in Pi Browser
  enablePiFeatures();
}

2. Implement Detection Function

Add this detection utility to your app:

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);
  }

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

3. Add Fallback UI

Create helpful UI for non-Pi Browser users:

function showFallbackUI() {
  document.getElementById('app').innerHTML = `
    <div class="fallback-message">
      <h3>Pi Features Available in Pi Browser</h3>
      <p>For full functionality, open this app in Pi Browser:</p>
      <a href="https://pinet.com/YOUR_APP_LINK">Open in Pi Browser</a>
    </div>
  `;
}

4. Make Authentication User-Initiated

Change from auto-login to button-triggered login:

// ❌ Before: Auto-login on page load
window.onload = () => {
  Pi.authenticate(['payments'], callback);
};

// ✅ After: User-initiated login
document.getElementById('login-btn').onclick = async () => {
  const isPiBrowser = await detectPiBrowser();
  if (!isPiBrowser) {
    alert('Please open this app in Pi Browser');
    return;
  }
  
  const auth = await Pi.authenticate(['payments'], callback);
  // Handle successful authentication
};

Common Migration Patterns

Pattern 1: Basic App Update

// Old approach
class OldPiApp {
  constructor() {
    // ❌ Immediate authentication
    Pi.authenticate(['payments'], this.onAuth.bind(this));
  }
}

// New hybrid approach  
class NewPiApp {
  constructor() {
    this.init();
  }

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

    this.setupPiFeatures();
  }

  showFallbackUI() {
    // Show helpful message for regular browser users
  }

  setupPiFeatures() {
    // Only setup Pi-specific functionality
    document.getElementById('login-btn').onclick = () => this.handleLogin();
  }

  async handleLogin() {
    const auth = await Pi.authenticate(['payments'], this.onIncompletePayment);
    // Handle authentication success
  }
}

Pattern 2: Payment Flow Update

// Old payment approach
function oldPaymentFlow() {
  // ❌ Direct payment call
  Pi.createPayment(paymentData, callbacks);
}

// New hybrid payment approach
async function newPaymentFlow() {
  const isPiBrowser = await detectPiBrowser();
  
  if (!isPiBrowser) {
    // Show QR code or Pi Browser link
    showPaymentFallback();
    return;
  }

  // Only create payment in Pi Browser
  const payment = await Pi.createPayment(paymentData, callbacks);
}

function showPaymentFallback() {
  document.getElementById('payment-section').innerHTML = `
    <div class="payment-fallback">
      <h3>Payments available in Pi Browser</h3>
      <img src="/qr-code.png" alt="Scan with Pi Browser" />
      <p>Scan this QR code with Pi Browser to make payments</p>
    </div>
  `;
}

Pattern 3: React Component Update

// Old React component
function OldLoginComponent() {
  useEffect(() => {
    // ❌ Auto-authenticate on mount
    Pi.authenticate(['payments'], callback);
  }, []);

  return <div>Auto-authenticating...</div>;
}

// New hybrid React component
function NewLoginComponent() {
  const isPiBrowser = useIsPiBrowser(); // Custom hook
  const [user, setUser] = useState(null);

  const handleLogin = async () => {
    try {
      const auth = await Pi.authenticate(['payments'], callback);
      setUser(auth.user);
    } catch (error) {
      console.error('Login failed:', error);
    }
  };

  if (isPiBrowser === null) return <div>Detecting Pi Browser...</div>;
  
  if (!isPiBrowser) {
    return (
      <div className="fallback">
        <h3>Login available in Pi Browser</h3>
        <a href="https://pinet.com/YOUR_APP">Open in Pi Browser</a>
      </div>
    );
  }

  return (
    <div>
      {!user ? (
        <button onClick={handleLogin}>Login with Pi</button>
      ) : (
        <div>Welcome, {user.uid}!</div>
      )}
    </div>
  );
}

Testing Your Migration

1. Test in Regular Browser

  • ✅ Should show fallback UI
  • ✅ No authentication popups
  • ✅ Clear messaging about Pi Browser requirement

2. Test in Pi Browser

  • ✅ Pi features work normally
  • ✅ Authentication flows properly
  • ✅ Payments work correctly

3. Test Edge Cases

  • ✅ Slow network connections
  • ✅ SDK loading failures
  • ✅ User cancellation flows

Common Issues and Solutions

Issue: Detection Takes Too Long

// Solution: Add loading state
function App() {
  const [isDetecting, setIsDetecting] = useState(true);
  const [isPiBrowser, setIsPiBrowser] = useState(null);

  useEffect(() => {
    detectPiBrowser().then(result => {
      setIsPiBrowser(result);
      setIsDetecting(false);
    });
  }, []);

  if (isDetecting) return <div>Loading...</div>;
  // Rest of component
}

Issue: Users Don't Understand Fallback UI

// Solution: Add more detailed messaging
function showDetailedFallback() {
  return `
    <div class="detailed-fallback">
      <h2>Welcome to Our Pi Network App!</h2>
      <p>This app integrates with Pi Network for secure payments and authentication.</p>
      
      <h3>To access all features:</h3>
      <ol>
        <li>Download Pi Browser from your app store</li>
        <li>Open this link in Pi Browser: <strong>pinet.com/YOUR_APP</strong></li>
        <li>Enjoy full Pi Network integration!</li>
      </ol>
      
      <div class="cta">
        <a href="https://pinet.com/YOUR_APP" class="big-button">
          Open in Pi Browser Now
        </a>
      </div>
    </div>
  `;
}

Issue: Fallback Detection Isn't Working

// Solution: Add more robust fallback detection
async function robustDetectPiBrowser() {
  // Try primary method
  try {
    if (window?.Pi?.getPiHostAppInfo) {
      const result = await Promise.race([
        window.Pi.getPiHostAppInfo(),
        new Promise(resolve => setTimeout(() => resolve("timeout"), 3000))
      ]);
      
      if (result?.hostApp === "pi-browser") return true;
    }
  } catch (e) {
    console.warn("Primary detection failed", e);
  }

  // Try multiple fallback methods
  const ua = navigator?.userAgent?.toLowerCase() || "";
  const referrer = document.referrer.toLowerCase();
  
  return ua.includes("pibrowser") || 
         ua.includes("pi-browser") ||
         referrer.includes("minepi.com") ||
         referrer.includes("pi.app") ||
         window.location.hostname.includes("pi.app");
}

Final Steps

  1. Update your SDK initialization to include detection
  2. Test thoroughly in both browser types
  3. Update your documentation to mention hybrid support
  4. Monitor user feedback for UX improvements
  5. Consider analytics to track browser type usage

Resources

Need Help?

If you encounter issues during migration:

  1. Check the Examples page for working code samples
  2. Review the Pi Browser Detection guide
  3. Test your detection logic in both environments
  4. Ensure proper error handling and fallbacks

The hybrid app approach is the future of Pi Network development - it provides better UX and broader reach while maintaining full Pi Network integration for Pi Browser users.

⚠️ **GitHub.com Fallback** ⚠️