Firefox Navigation Bug with Razorpay Payment Gateway - Here's the Fix
Lokesh

Lokesh @lokisri

Joined:
Sep 19, 2023

Firefox Navigation Bug with Razorpay Payment Gateway - Here's the Fix

Publish Date: Oct 13
1 0

I recently encountered a frustrating bug while integrating Razorpay payment gateway in a Next.js application. After completing a payment, Firefox would automatically navigate back to the previous page (flight results in my case), while Chrome, Safari, and Edge worked perfectly fine.

Symptoms:

  • Payment completes successfully
  • Verification loading spinner appears briefly
  • Firefox suddenly navigates back to the previous page
  • Success message never displays
  • Issue is Firefox-specific only

Console Warnings (Red Herrings)

Firefox threw several warnings that initially seemed related:
However, these were not the root cause - the real issue was Firefox's handling of window.history when the Razorpay modal closes.

Root Cause 🔍

Firefox treats the Razorpay modal closure differently than other browsers. When the payment modal closes, Firefox interprets it as a navigation event and triggers a popstate event, causing the browser to go back in history.

The Solution ✅

The fix involves preventing Firefox from navigating back by managing the browser history state:


typescript
const onPayClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
  e.preventDefault();

  try {
    // Your existing order creation and Razorpay script loading...
    const order = await createOrder(fixedAmount, id);
    const loaded = await loadRazorpayScript();
    if (!loaded) throw new Error('Razorpay SDK failed to load');

    // 🔥 FIX: Prevent Firefox back navigation
    const preventBackNav = (e: PopStateEvent) => {
      window.history.pushState(null, '', window.location.href);
    };

    // Push initial state
    window.history.pushState(null, '', window.location.href);
    window.addEventListener('popstate', preventBackNav);

    const options = {
      key: process.env.NEXT_PUBLIC_RAZORPAY_KEY_ID,
      amount: order.amount,
      currency: order.currency,
      name: 'Your Company',
      order_id: order.id,

      handler: async (response: any) => {
        // ✅ Clean up listener on success
        window.removeEventListener('popstate', preventBackNav);

        setIsVerifying(true);

        try {
          // Your payment verification logic...
          const data = await verifyPayment(response, id);

          if (data.success) {
            setBookingDetails(data);
            // Show success message
          }
        } catch (err) {
          console.error('Verification error:', err);
        } finally {
          setIsVerifying(false);
        }
      },

      modal: {
        ondismiss: () => {
          // ✅ Clean up listener on modal dismiss
          window.removeEventListener('popstate', preventBackNav);
          console.log('Checkout closed by user');
        },
      },
    };

    const rzp = new window.Razorpay(options);

    rzp.on('payment.failed', (resp: any) => {
      // ✅ Clean up listener on payment failure
      window.removeEventListener('popstate', preventBackNav);
      console.error('Payment failed:', resp.error);
    });

    rzp.open();
  } catch (err) {
    console.error('Payment flow error:', err);
  }
};
Enter fullscreen mode Exit fullscreen mode

Comments 0 total

    Add comment