{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["sub-heading","admonition"]},"type":"markdown"},"seo":{"title":"Troubleshooting","description":"Transform your commerce with PXP's unified platform—seamless payments, real-time insights, and global growth in one powerful integration.","lang":"en-UK","siteUrl":"https://developer.pxp.io","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"troubleshooting","__idx":0},"children":["Troubleshooting"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Learn how to diagnose and fix common issues with Checkout Drop-in."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"quick-diagnostics","__idx":1},"children":["Quick diagnostics"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you're experiencing issues with Drop-in, start with these quick diagnostic checks:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import CheckoutDropIn from '@pxpio/web-components-sdk/src/checkoutDropIn/CheckoutDropIn';\n\n// Drop-in diagnostic helper\nfunction diagnoseDropIn() {\n  console.group('Checkout Drop-in diagnostics');\n  \n  // Check SDK installation\n  console.log('SDK imported:', typeof CheckoutDropIn !== 'undefined');\n  \n  // Check container exists\n  const container = document.getElementById('checkout-drop-in-container');\n  console.log('Container exists:', !!container);\n  console.log('Container visible:', container ? container.offsetParent !== null : false);\n  \n  // Check session data\n  console.log('Session ID:', sessionData?.sessionId ? 'Present' : 'Missing');\n  console.log('HMAC key:', sessionData?.hmacKey ? 'Present' : 'Missing');\n  console.log('Allowed funding types:', sessionData?.allowedFundingTypes);\n  \n  // Check environment\n  console.log('Environment:', config.environment);\n  console.log('Owner ID:', config.ownerId);\n  console.log('Protocol:', location.protocol);\n  console.log('Hostname:', location.hostname);\n  \n  console.groupEnd();\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"common-issues","__idx":2},"children":["Common issues"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"drop-in-not-rendering","__idx":3},"children":["Drop-in not rendering"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Symptoms:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["There's an empty container where the drop-in should appear."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No payment methods are visible."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["There are no errors in the console."]}]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Cause"},"children":["Cause"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Solution"},"children":["Solution"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Container ID mismatch."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Verify that the container ID in your HTML matches the ID passed to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["create()"]},". IDs are case-sensitive."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Container not in DOM."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Ensure that the container element exists in the DOM before calling ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["create()"]},". Check the timing in React/Vue lifecycles. Use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["useEffect"]}," in React to ensure DOM is ready."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Session data invalid."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Verify session data includes ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sessionId"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["hmacKey"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allowedFundingTypes"]},". Check backend session creation."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No payment methods enabled."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Check ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allowedFundingTypes"]}," in your session. At least one payment method must be enabled in the Unity Portal."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["CSS conflicts."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Check browser DevTools for CSS issues. Drop-in uses modern CSS that may conflict with old stylesheets."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Diagnostic steps:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"async function diagnoseRenderingIssue() {\n  // Step 1: Verify container\n  const containerId = 'checkout-drop-in-container';\n  const container = document.getElementById(containerId);\n  \n  if (!container) {\n    console.error(`Container with ID \"${containerId}\" not found in DOM`);\n    return;\n  }\n  console.log('Container found');\n  \n  // Step 2: Check container visibility\n  const rect = container.getBoundingClientRect();\n  if (rect.width === 0 || rect.height === 0) {\n    console.warn('Container has zero dimensions:', rect);\n  } else {\n    console.log('Container has dimensions:', rect);\n  }\n  \n  // Step 3: Verify session data\n  const sessionData = await fetch('/api/create-session').then(r => r.json());\n  \n  if (!sessionData.sessionId) {\n    console.error('Session ID missing');\n    return;\n  }\n  console.log('Session ID present:', sessionData.sessionId);\n  \n  if (!sessionData.allowedFundingTypes) {\n    console.error('No allowed funding types in session');\n    return;\n  }\n  console.log('Allowed funding types:', sessionData.allowedFundingTypes);\n  \n  // Step 4: Count available payment methods\n  let paymentMethodCount = 0;\n  if (sessionData.allowedFundingTypes.cards) paymentMethodCount++;\n  if (sessionData.allowedFundingTypes.wallets?.paypal) paymentMethodCount++;\n  if (sessionData.allowedFundingTypes.wallets?.googlePay) paymentMethodCount++;\n  if (sessionData.allowedFundingTypes.wallets?.applePay) paymentMethodCount++;\n  \n  if (paymentMethodCount === 0) {\n    console.error('No payment methods enabled in session');\n    return;\n  }\n  console.log(`${paymentMethodCount} payment method(s) available`);\n  \n  // Step 5: Try initialisation\n  try {\n    const checkoutDropIn = CheckoutDropIn.initialize({\n      environment: 'test',\n      session: sessionData,\n      ownerId: 'TEST',\n      ownerType: 'MerchantGroup',\n      transactionData: {\n        currency: 'USD',\n        amount: 1.00,\n        entryType: 'Ecom',\n        intent: {\n          card: IntentType.Authorisation,\n          paypal: IntentType.Purchase\n        },\n        merchantTransactionId: 'test-' + Date.now(),\n        merchantTransactionDate: () => new Date().toISOString()\n      },\n      onGetShopper: () => Promise.resolve({ id: 'test-shopper' }),\n      onSuccess: () => {},\n      onError: () => {}\n    });\n    \n    console.log('Drop-in initialised successfully');\n    \n    checkoutDropIn.create(containerId);\n    console.log('Drop-in mounted successfully');\n  } catch (error) {\n    console.error('Initialisation failed:', error);\n  }\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"session-expired-errors","__idx":4},"children":["Session expired errors"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Symptoms:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"Session expired\""]}," error message is displayed."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The drop-in loads but payment fails immediately."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The console shows session timeout errors."]}]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Cause"},"children":["Cause"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Solution"},"children":["Solution"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Session timeout exceeded."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Sessions expire based on the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sessionTimeout"]}," value (default = 120 minutes). Create a new session if expired."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Clock skew"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Ensure that the server and client clocks are synchronised. Use NTP for the server time."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Session reused"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Sessions are single-use. Create a new session for each checkout attempt."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Invalid HMAC signature"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Verify that the HMAC key matches between session creation and SDK initialisation."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Solution: Implement session refresh"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import CheckoutDropIn from '@pxpio/web-components-sdk/src/checkoutDropIn/CheckoutDropIn';\nimport IntentType from '@pxpio/web-components-sdk/src/basePxpCheckout/types/IntentType';\n\nasync function initializeWithSessionRefresh() {\n  let sessionData = await getSessionFromBackend();\n  \n  const checkoutDropIn = CheckoutDropIn.initialize({\n    environment: 'production',\n    session: sessionData,\n    ownerId: 'MERCHANT-1',\n    ownerType: 'MerchantGroup',\n    transactionData: {\n      currency: 'USD',\n      amount: 25.00,\n      entryType: 'Ecom',\n      intent: {\n        card: IntentType.Authorisation,\n        paypal: IntentType.Authorisation\n      },\n      merchantTransactionId: crypto.randomUUID(),\n      merchantTransactionDate: () => new Date().toISOString()\n    },\n    onGetShopper: () => Promise.resolve({ id: 'shopper-001' }),\n    onSuccess: (result) => handleSuccess(result),\n    onError: async (error) => {\n      // Handle session expiry\n      if (error.code === 'SESSION_EXPIRED' || error.message.includes('expired')) {\n        console.log('Session expired, refreshing...');\n        \n        try {\n          // Destroy old instance first to prevent memory leaks\n          checkoutDropIn.destroy();\n          \n          // Get new session\n          sessionData = await getSessionFromBackend();\n          \n          // Reinitialise Drop-in\n          const newDropIn = CheckoutDropIn.initialize({\n            environment: 'production',\n            session: sessionData,\n            ownerId: 'MERCHANT-1',\n            ownerType: 'MerchantGroup',\n            transactionData: {\n              currency: 'USD',\n              amount: 25.00,\n              entryType: 'Ecom',\n              intent: {\n                card: IntentType.Authorisation,\n                paypal: IntentType.Authorisation\n              },\n              merchantTransactionId: crypto.randomUUID(),\n              merchantTransactionDate: () => new Date().toISOString()\n            },\n            onGetShopper: () => Promise.resolve({ id: 'shopper-001' }),\n            onSuccess: (result) => handleSuccess(result),\n            onError: (error) => handleError(error)\n          });\n          \n          newDropIn.create('checkout-drop-in-container');\n          alert('Session refreshed. Please try your payment again.');\n        } catch (refreshError) {\n          console.error('Failed to refresh session:', refreshError);\n          alert('Unable to refresh payment session. Please refresh the page.');\n        }\n      } else {\n        handleError(error);\n      }\n    }\n  });\n  \n  checkoutDropIn.create('checkout-drop-in-container');\n}\n\nasync function getSessionFromBackend() {\n  const response = await fetch('/api/create-session', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({\n      amount: 25.00,\n      currency: 'USD'\n    })\n  });\n  \n  if (!response.ok) {\n    throw new Error('Failed to create session');\n  }\n  \n  return response.json();\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"payment-method-not-appearing","__idx":5},"children":["Payment method not appearing"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Symptoms:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["An expected payment method isn't shown."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Only the card payment method is visible."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The payment method briefly appears then disappears."]}]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Payment method"},"children":["Payment method"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Common causes"},"children":["Common causes"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Solutions"},"children":["Solutions"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Cards"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Cards aren't enabled in the Unity Portal."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Missing `allowedFundingTypes.cards` in the session."]}]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Enable the Card service in the Unity Portal."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify that the session includes the `cards` array"]}]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["PayPal"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["PayPal onboarding wasn't completed."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Missing `allowedFundingTypes.wallets.paypal`."]}]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Complete [PayPal onboarding]."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify that the session includes PayPal configuration."]}]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Google Pay"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Unsupported browser or device."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Missing merchant ID in session."]}]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Google Pay works on several browsers (Chrome, Edge, Opera, and more)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Configure Google Pay in the Unity Portal."]}]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Apple Pay"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Unsupported browser or device."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Unsupported device (no Touch ID/Face ID)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["HTTPS required."]}]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Apple Pay works on several browsers (Safari, Chrome, Edge, and more)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Configure Apple Pay in the Unity Portal."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Device must have biometric authentication."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Use HTTPS (or localhost for testing)."]}]}]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Diagnostic steps:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"function diagnosePaymentMethodVisibility() {\n  console.group('Payment method diagnostics');\n  \n  // Check session funding types\n  const session = sessionData;\n  const fundingTypes = session?.allowedFundingTypes;\n  \n  console.log('Session funding types:', fundingTypes);\n  \n  // Check cards\n  if (fundingTypes?.cards) {\n    console.log('Cards enabled:', fundingTypes.cards);\n  } else {\n    console.warn('Cards not enabled in session');\n  }\n  \n  // Check PayPal\n  if (fundingTypes?.wallets?.paypal) {\n    console.log('PayPal enabled:', fundingTypes.wallets.paypal);\n  } else {\n    console.warn('PayPal not enabled in session');\n  }\n  \n  // Check Google Pay\n  if (fundingTypes?.wallets?.googlePay) {\n    console.log('Google Pay configuration present');\n    \n    // Check browser compatibility\n    const isChromiumBrowser = /Chrome|Edg|OPR/.test(navigator.userAgent);\n    if (isChromiumBrowser) {\n      console.log('Browser supports Google Pay');\n    } else {\n      console.warn('Browser does not support Google Pay (Chrome/Edge/Opera required)');\n    }\n  } else {\n    console.warn('Google Pay not configured in session');\n  }\n  \n  // Check Apple Pay\n  if (fundingTypes?.wallets?.applePay) {\n    console.log('Apple Pay configuration present');\n    \n    // Check browser compatibility\n    const isSafari = /Safari/.test(navigator.userAgent) && !(/Chrome|Chromium|Edge|OPR/.test(navigator.userAgent));\n    if (isSafari) {\n      console.log('Browser is Safari');\n      \n      // Check Apple Pay availability\n      if (window.ApplePaySession) {\n        if (ApplePaySession.canMakePayments()) {\n          console.log('Apple Pay available on this device');\n        } else {\n          console.warn('Apple Pay not set up on this device');\n        }\n      } else {\n        console.warn('ApplePaySession not available');\n      }\n    } else {\n      console.warn('Browser is not Safari (required for Apple Pay)');\n    }\n    \n    // Check HTTPS\n    if (location.protocol === 'https:' || location.hostname === 'localhost') {\n      console.log('HTTPS requirement met');\n    } else {\n      console.warn('HTTPS required for Apple Pay');\n    }\n  } else {\n    console.warn('Apple Pay not configured in session');\n  }\n  \n  console.groupEnd();\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"paypal-popup-blocked","__idx":6},"children":["PayPal popup blocked"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Symptoms:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The PayPal window doesn't open."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"Popup blocked\""]}," message is displayed in the browser."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The payment fails without any visible error."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Solution:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"// Detect and handle popup blocker\nfunction checkPopupBlocker() {\n  // Try opening a test window\n  const testWindow = window.open('', '_blank', 'width=1,height=1');\n  \n  if (!testWindow || testWindow.closed || typeof testWindow.closed === 'undefined') {\n    // Popup blocked\n    return true;\n  }\n  \n  testWindow.close();\n  return false;\n}\n\n// Show warning if popup blocker detected\nif (checkPopupBlocker()) {\n  console.warn('Popup blocker detected');\n  \n  // Show user-friendly message\n  const warningDiv = document.createElement('div');\n  warningDiv.className = 'popup-warning';\n  warningDiv.innerHTML = `\n    <div class=\"warning-content\">\n      <h4>Enable Popups</h4>\n      <p>PayPal requires popup windows. Please allow popups for this site and try again.</p>\n      <button onclick=\"this.parentElement.parentElement.remove()\">Got it</button>\n    </div>\n  `;\n  \n  document.getElementById('checkout-drop-in-container').prepend(warningDiv);\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"backend-verification-failing","__idx":7},"children":["Backend verification failing"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Symptoms:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Frontend ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," fires but backend verification fails."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Orders aren't being fulfilled."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["There are ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"Payment verification failed\""]}," errors."]}]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Cause"},"children":["Cause"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Solution"},"children":["Solution"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Webhook not configured."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Set up a webhook URL in the Unity Portal and implement a webhook handler on your backend."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Webhook authentication failing."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Verify your webhook signature/authentication. Check your HMAC implementation."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Race condition (GET before webhook)."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Implement a fallback to the Query Transaction API if the webhook hasn't arrived yet."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Amount mismatch."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Ensure that the amount in the verification request exactly matches the transaction amount."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Transaction ID mismatch"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Verify that the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["systemTransactionId"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["merchantTransactionId"]}," match database records."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Solution: Robust backend verification"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"// Backend webhook handler (Node.js/Express example)\napp.post('/webhooks/pxp', async (req, res) => {\n  try {\n    const events = req.body;\n    \n    // Verify webhook authenticity using HMAC (implement based on Unity webhook auth)\n    if (!verifyWebhookSignature(req)) {\n      console.error('Invalid webhook signature');\n      return res.status(401).json({ error: 'Unauthorised' });\n    }\n    \n    for (const event of events) {\n      if (event.eventCategory === 'Transaction') {\n        const txn = event.eventData;\n        \n        console.log('Processing transaction:', txn.systemTransactionId);\n        \n        // Idempotency check\n        const existing = await db.transactions.findOne({\n          systemTransactionId: txn.systemTransactionId\n        });\n        \n        if (existing) {\n          console.log('Transaction already processed, skipping');\n          continue;\n        }\n        \n        // Verify transaction state\n        if (txn.state === 'Authorised' || txn.state === 'Captured') {\n          // Find order by merchant transaction ID\n          const order = await db.orders.findOne({\n            transactionId: txn.merchantTransactionId\n          });\n          \n          if (!order) {\n            console.error('Order not found:', txn.merchantTransactionId);\n            continue;\n          }\n          \n          // Verify amount matches (use appropriate field name from webhook payload)\n          const transactionAmount = txn.amounts?.transactionValue || txn.amount;\n          if (Math.abs(transactionAmount - order.amount) > 0.01) {\n            console.error('Amount mismatch:', {\n              expected: order.amount,\n              actual: transactionAmount\n            });\n            continue;\n          }\n          \n          // Mark transaction as processed\n          await db.transactions.create({\n            systemTransactionId: txn.systemTransactionId,\n            merchantTransactionId: txn.merchantTransactionId,\n            amount: transactionAmount,\n            state: txn.state,\n            processedAt: new Date()\n          });\n          \n          // Fulfill order\n          await fulfillOrder(order.id, txn.systemTransactionId);\n          \n          console.log('Order fulfilled:', order.id);\n        }\n      }\n    }\n    \n    // Always return success\n    res.json({ state: 'Success' });\n  } catch (error) {\n    console.error('Webhook processing error:', error);\n    res.status(500).json({ error: 'Internal server error' });\n  }\n});\n\n// Frontend verification endpoint (fallback)\napp.post('/api/verify-payment', async (req, res) => {\n  const { systemTransactionId, merchantTransactionId, amount } = req.body;\n  \n  try {\n    // Check if webhook already processed this\n    const existing = await db.transactions.findOne({ systemTransactionId });\n    \n    if (existing) {\n      const order = await db.orders.findOne({\n        transactionId: merchantTransactionId\n      });\n      \n      return res.json({\n        success: true,\n        orderId: order.id,\n        source: 'webhook'\n      });\n    }\n    \n    // Fallback: Query PXP API\n    // NOTE: You must implement HMAC authentication for PXP API calls\n    // See the Backend Implementation section in the integration guide for HMAC details\n    const response = await fetch(\n      `https://api-services.pxp.io/api/v1/transactions?systemTransactionId=${systemTransactionId}&fundingType=Card`,\n      {\n        headers: {\n          'X-Client-Id': process.env.PXP_CLIENT_ID,\n          'X-Request-Id': crypto.randomUUID(),\n          'Authorization': createAuthHeader('/api/v1/transactions', '', process.env.PXP_TOKEN_ID, process.env.PXP_TOKEN_VALUE)\n        }\n      }\n    );\n    \n    if (!response.ok) {\n      throw new Error('PXP API request failed');\n    }\n    \n    const transaction = await response.json();\n    \n    // Verify transaction\n    if (transaction.state !== 'Authorised' && transaction.state !== 'Captured') {\n      return res.json({ success: false, error: 'Transaction not authorised' });\n    }\n    \n    // Use appropriate field name from API response\n    const transactionAmount = transaction.amounts?.transactionValue || transaction.amount;\n    if (Math.abs(transactionAmount - amount) > 0.01) {\n      return res.json({ success: false, error: 'Amount mismatch' });\n    }\n    \n    if (transaction.merchantTransactionId !== merchantTransactionId) {\n      return res.json({ success: false, error: 'Transaction ID mismatch' });\n    }\n    \n    // Find and fulfill order\n    const order = await db.orders.findOne({ transactionId: merchantTransactionId });\n    \n    if (!order) {\n      return res.json({ success: false, error: 'Order not found' });\n    }\n    \n    // Record transaction\n    const transactionAmount = transaction.amounts?.transactionValue || transaction.amount;\n    await db.transactions.create({\n      systemTransactionId,\n      merchantTransactionId,\n      amount: transactionAmount,\n      state: transaction.state,\n      processedAt: new Date(),\n      source: 'api_fallback'\n    });\n    \n    // Fulfill order\n    await fulfillOrder(order.id, systemTransactionId);\n    \n    res.json({\n      success: true,\n      orderId: order.id,\n      source: 'api'\n    });\n  } catch (error) {\n    console.error('Payment verification error:', error);\n    res.status(500).json({ success: false, error: 'Verification failed' });\n  }\n});\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"framework-specific-issues","__idx":8},"children":["Framework-specific issues"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"react-drop-in-not-mounting","__idx":9},"children":["React: Drop-in not mounting"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Symptoms:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The drop-in doesn't appear in the React component."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["There are ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"Container not found\""]}," errors."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["There are mount/unmount timing issues."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Solution:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import { useEffect, useRef } from 'react';\nimport CheckoutDropIn from '@pxpio/web-components-sdk/src/checkoutDropIn/CheckoutDropIn';\nimport IntentType from '@pxpio/web-components-sdk/src/basePxpCheckout/types/IntentType';\n\nexport default function CheckoutPage() {\n  const dropInRef = useRef(null);\n  const mountedRef = useRef(false);\n\n  useEffect(() => {\n    // Prevent double-mounting in React StrictMode\n    if (mountedRef.current) return;\n    mountedRef.current = true;\n\n    async function initializeDropIn() {\n      try {\n        const sessionData = await fetch('/api/create-session')\n          .then(r => r.json());\n\n        const checkoutDropIn = CheckoutDropIn.initialize({\n          environment: 'production',\n          session: sessionData,\n          ownerId: 'MERCHANT-1',\n          ownerType: 'MerchantGroup',\n          transactionData: {\n            currency: 'USD',\n            amount: 25.00,\n            entryType: 'Ecom',\n            intent: {\n              card: IntentType.Authorisation,\n              paypal: IntentType.Authorisation\n            },\n            merchantTransactionId: crypto.randomUUID(),\n            merchantTransactionDate: () => new Date().toISOString()\n          },\n          onGetShopper: () => Promise.resolve({ id: 'shopper-001' }),\n          onSuccess: (result) => handleSuccess(result),\n          onError: (error) => handleError(error)\n        });\n\n        // Store reference for cleanup\n        dropInRef.current = checkoutDropIn;\n\n        // Mount Drop-in to DOM\n        checkoutDropIn.create('checkout-drop-in-container');\n      } catch (error) {\n        console.error('Failed to initialise Drop-in:', error);\n      }\n    }\n\n    initializeDropIn();\n\n    // Cleanup on unmount - always call destroy() to prevent memory leaks\n    return () => {\n      if (dropInRef.current) {\n        dropInRef.current.destroy();\n      }\n    };\n  }, []); // Empty dependency array - run once\n\n  return (\n    <div className=\"checkout-page\">\n      <h1>Complete your purchase</h1>\n      <div id=\"checkout-drop-in-container\"></div>\n    </div>\n  );\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"vue-reactivity-issues","__idx":10},"children":["Vue: Reactivity issues"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Solution:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"vue","header":{"controls":{"copy":{}}},"source":"<template>\n  <div class=\"checkout-page\">\n    <h1>Complete your purchase</h1>\n    <div id=\"checkout-drop-in-container\"></div>\n  </div>\n</template>\n\n<script setup>\nimport { onMounted, onUnmounted, ref } from 'vue';\nimport CheckoutDropIn from '@pxpio/web-components-sdk/src/checkoutDropIn/CheckoutDropIn';\nimport IntentType from '@pxpio/web-components-sdk/src/basePxpCheckout/types/IntentType';\n\nconst checkoutDropIn = ref(null);\n\nonMounted(async () => {\n  try {\n    const sessionData = await fetch('/api/create-session')\n      .then(r => r.json());\n\n    checkoutDropIn.value = CheckoutDropIn.initialize({\n      environment: 'production',\n      session: sessionData,\n      ownerId: 'MERCHANT-1',\n      ownerType: 'MerchantGroup',\n      transactionData: {\n        currency: 'USD',\n        amount: 25.00,\n        entryType: 'Ecom',\n        intent: {\n          card: IntentType.Authorisation,\n          paypal: IntentType.Authorisation\n        },\n        merchantTransactionId: crypto.randomUUID(),\n        merchantTransactionDate: () => new Date().toISOString()\n      },\n      onGetShopper: () => Promise.resolve({ id: 'shopper-001' }),\n      onSuccess: (result) => handleSuccess(result),\n      onError: (error) => handleError(error)\n    });\n\n    checkoutDropIn.value.create('checkout-drop-in-container');\n  } catch (error) {\n    console.error('Failed to initialise Drop-in:', error);\n  }\n});\n\nonUnmounted(() => {\n  if (checkoutDropIn.value) {\n    checkoutDropIn.value.destroy();\n  }\n});\n\nfunction handleSuccess(result) {\n  console.log('Payment successful:', result);\n}\n\nfunction handleError(error) {\n  console.error('Payment failed:', error);\n}\n</script>\n","lang":"vue"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"error-codes-reference","__idx":11},"children":["Error codes reference"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For a complete list of error codes and their meanings, see the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/drop-in/web/error-handling"},"children":["Error handling"]}," guide."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"getting-additional-help","__idx":12},"children":["Getting additional help"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you're still experiencing issues, try these troubleshooting steps."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"enable-debug-mode","__idx":13},"children":["Enable debug mode"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Add detailed logging using the analytics event handler:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"const checkoutDropIn = CheckoutDropIn.initialize({\n  // ... your config\n  analyticsEvent: (event) => {\n    console.log('Drop-in analytics event:', event);\n  }\n});\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"collect-diagnostic-information","__idx":14},"children":["Collect diagnostic information"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When contacting support, include:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"function collectDiagnosticInfo() {\n  const info = {\n    // Browser information\n    userAgent: navigator.userAgent,\n    platform: navigator.platform,\n    language: navigator.language,\n    \n    // Screen information\n    screenWidth: window.screen.width,\n    screenHeight: window.screen.height,\n    viewport: {\n      width: window.innerWidth,\n      height: window.innerHeight\n    },\n    \n    // Environment\n    protocol: location.protocol,\n    hostname: location.hostname,\n    url: location.href,\n    \n    // SDK information\n    sdkVersion: '1.0.0', // Replace with actual version\n    environment: 'production',\n    \n    // Session info (sanitised)\n    sessionIdPresent: !!sessionData?.sessionId,\n    allowedFundingTypes: sessionData?.allowedFundingTypes,\n    \n    // Timestamp\n    timestamp: new Date().toISOString()\n  };\n  \n  console.log('Diagnostic information:', JSON.stringify(info, null, 2));\n  \n  // Copy to clipboard for easy sharing\n  navigator.clipboard?.writeText(JSON.stringify(info, null, 2));\n  \n  return info;\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When contacting support, always include your merchant ID, environment (test/production), and any relevant error messages or console logs."]}]}]},"headings":[{"value":"Troubleshooting","id":"troubleshooting","depth":1},{"value":"Quick diagnostics","id":"quick-diagnostics","depth":2},{"value":"Common issues","id":"common-issues","depth":2},{"value":"Drop-in not rendering","id":"drop-in-not-rendering","depth":3},{"value":"Session expired errors","id":"session-expired-errors","depth":3},{"value":"Payment method not appearing","id":"payment-method-not-appearing","depth":3},{"value":"PayPal popup blocked","id":"paypal-popup-blocked","depth":3},{"value":"Backend verification failing","id":"backend-verification-failing","depth":3},{"value":"Framework-specific issues","id":"framework-specific-issues","depth":2},{"value":"React: Drop-in not mounting","id":"react-drop-in-not-mounting","depth":3},{"value":"Vue: Reactivity issues","id":"vue-reactivity-issues","depth":3},{"value":"Error codes reference","id":"error-codes-reference","depth":2},{"value":"Getting additional help","id":"getting-additional-help","depth":2},{"value":"Enable debug mode","id":"enable-debug-mode","depth":3},{"value":"Collect diagnostic information","id":"collect-diagnostic-information","depth":3}],"frontmatter":{"seo":{"title":"Troubleshooting"}},"lastModified":"2026-05-06T10:44:47.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/drop-in/web/troubleshooting","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}