Migration Guide - alxspiker/Pi-Network-Developer-Docs GitHub Wiki
Transform your existing Pi Network app to work seamlessly across all environments
Step-by-step guide to implementing hybrid Web2/Web3 compatibility
Step-by-step guide to implementing hybrid Web2/Web3 compatibility
🚀 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
🔧 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 |
📋 Essential steps to upgrade your existing Pi Network application
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();
}
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");
}
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>
`;
}
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
};
// 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
}
}
// 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>
`;
}
// 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>
);
}
- ✅ Should show fallback UI
- ✅ No authentication popups
- ✅ Clear messaging about Pi Browser requirement
- ✅ Pi features work normally
- ✅ Authentication flows properly
- ✅ Payments work correctly
- ✅ Slow network connections
- ✅ SDK loading failures
- ✅ User cancellation flows
// 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
}
// 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>
`;
}
// 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");
}
- Update your SDK initialization to include detection
- Test thoroughly in both browser types
- Update your documentation to mention hybrid support
- Monitor user feedback for UX improvements
- Consider analytics to track browser type usage
- Pi Browser Detection Guide - Complete implementation guide
- Examples - Updated code samples
- SDK Reference - API documentation with hybrid patterns
If you encounter issues during migration:
- Check the Examples page for working code samples
- Review the Pi Browser Detection guide
- Test your detection logic in both environments
- 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.