Skip to content

WebGL PayStation “CLOSE” event never triggers cancel callback due to incorrect undefined check #89

@GladFox

Description

@GladFox

WebGL PayStation CLOSE event never triggers cancel (wrong undefined check)

Summary

In the WebGL PayStation widget integration, when a player closes the PayStation window manually, the Unity-side “payment canceled” callback is not triggered. This prevents the client from detecting cancellation in real time and can leave purchases in a “pending” state unless the game implements polling (inventory/order status) as a workaround.

Environment

  • Unity WebGL build
  • Xsolla Unity SDK (PayStation widget / embed flow)
  • File: Assets/Xsolla/Core/Plugins/paystation.jslib

Observed behavior

When the user closes PayStation manually:

  • Module.SendMessage('XsollaWebCallbacks', 'PublishPaymentCancel') is not sent
  • Unity-side XsollaWebCallbacks.PublishPaymentCancel() is not called
  • OrderTrackerByPaystationCallbacks.HandlePaymentCancel() is not executed
  • tracking may continue and the order may stay in new
  • client code does not receive a “canceled by user” signal (often onBrowseClosed is never invoked as a result)

Expected behavior

When the user closes PayStation manually:

  • WebGL plugin should send PublishPaymentCancel to Unity
  • Unity-side order tracker should stop promptly and the game should be notified immediately (no polling needed for cancel)

Root cause analysis

The current WebGL plugin code treats “cancel” as:

if (data === 'undefined') {
  Module.SendMessage('XsollaWebCallbacks', 'PublishPaymentCancel');
}

But in JavaScript, if data is missing it is the primitive undefined (or sometimes null), not the string 'undefined'.
Therefore the condition is always false and the cancel path never runs.

Reproduction (minimal)

  1. Start a WebGL build with Xsolla PayStation widget enabled.
  2. Initiate a purchase so the PayStation widget opens.
  3. Close the widget manually using the close button / overlay close / ESC (depending on configuration).
  4. Observe: Unity does not receive a cancellation callback.

Fix

Replace the string comparison with a proper JS check for undefined / null.

Patch (diff)

diff --git a/Assets/Xsolla/Core/Plugins/paystation.jslib b/Assets/Xsolla/Core/Plugins/paystation.jslib
index 6cece9b2cf..bb18dce06b 100644
--- a/Assets/Xsolla/Core/Plugins/paystation.jslib
+++ b/Assets/Xsolla/Core/Plugins/paystation.jslib
@@ -120,10 +120,11 @@ mergeInto(LibraryManager.library, {
 			});

             XPayStationWidget.on(XPayStationWidget.eventTypes.CLOSE, function (event, data) {
-				if (data === 'undefined') {
+				// data is usually undefined/null when user closes PayStation manually.
+				// Treat that case as "cancel" so the Unity side can stop tracking and react immediately.
+				if (typeof data === 'undefined' || data === null) {
 					Module.SendMessage('XsollaWebCallbacks', 'PublishPaymentCancel');
-				}
-				else {
+				} else {
 					Module.SendMessage('XsollaWebCallbacks', 'PublishPaymentStatusUpdate');
 				}
 			});

Final code snippet (for reference)

XPayStationWidget.on(XPayStationWidget.eventTypes.CLOSE, function (event, data) {
  // data is usually undefined/null when user closes PayStation manually.
  // Treat that case as "cancel" so the Unity side can stop tracking and react immediately.
  if (typeof data === 'undefined' || data === null) {
    Module.SendMessage('XsollaWebCallbacks', 'PublishPaymentCancel');
  } else {
    Module.SendMessage('XsollaWebCallbacks', 'PublishPaymentStatusUpdate');
  }
});

Impact / why it matters

  • Without this fix, WebGL clients cannot reliably detect user cancellation via SDK callbacks.
  • Games are forced to implement polling (inventory/order status) to “unstick” the UI.
  • This causes poor UX (stuck “processing purchase” states) and complicates integration.

Notes

This fix is safe: it only changes how the CLOSE payload is interpreted, aligning it with standard JavaScript behavior (undefined/null).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions