Troubleshooting Guide
This guide helps you diagnose and resolve common issues you might encounter when using the PaySight Widget SDK.
Common Issues
Symptoms:
- Widget container remains empty
ERROR
event with initialization error
- Console errors related to script loading
Possible Causes:
- Invalid script source
- Network connectivity issues
- Invalid configuration
- DOM target element not found
Solutions:
- Check Script Loading
<!-- Ensure correct script URL -->
<script src="https://payment.paysight.io/widget-sdk.js"></script>
<!-- Add error handling -->
<script>
const script = document.createElement('script');
script.src = 'https://payment.paysight.io/widget-sdk.js';
script.onerror = (error) => {
console.error('Failed to load widget SDK:', error);
};
document.body.appendChild(script);
</script>
- Verify Configuration
// Ensure all required fields are present
const config = {
productId: 'prod_123', // Required
sessionId: 'session_123', // Required
amount: 2999, // Required
currency: 'USD' // Required
};
// Add error handling
try {
const widget = PaySightSDK.createWidget({
targetId: 'widget-container',
config,
onError: (error) => {
console.error('Widget initialization error:', error);
}
});
} catch (error) {
console.error('Failed to create widget:', error);
}
- Check DOM Target
const targetElement = document.getElementById('widget-container');
if (!targetElement) {
console.error('Widget container not found');
return;
}
// Ensure container is visible and has dimensions
if (targetElement.offsetWidth === 0 || targetElement.offsetHeight === 0) {
console.warn('Widget container has no dimensions');
}
Payment Processing
Payment Fails with 3DS Error
Symptoms:
- Payment fails during 3DS verification
PAYMENT_3DS_ERROR
event
- User sees 3DS popup but verification fails
Solutions:
- Enable 3DS Debugging
const config = {
threeDSRequired: true,
debug: true,
callbacks: {
onMessage: (message) => {
if (message.type.includes('3DS')) {
console.log('3DS Event:', message);
}
}
}
};
- Handle 3DS Events Properly
function handle3DSFlow(message) {
switch (message.type) {
case 'PAYMENT_3DS_START':
showLoadingUI('Starting 3D Secure verification...');
break;
case 'PAYMENT_3DS_ERROR':
const { code, message: errorMessage } = message.payload;
if (code === '3DS_TIMEOUT') {
retryPayment();
} else if (code === '3DS_NOT_SUPPORTED') {
fallbackToNon3DS();
} else {
showError(errorMessage);
}
break;
}
}
Symptoms:
- Intermittent payment failures
- Network timeout errors
ERROR
events
Solutions:
- Implement Retry Logic
class PaymentProcessor {
constructor(widget) {
this.widget = widget;
this.retryCount = 0;
this.maxRetries = 3;
}
async processPayment() {
try {
await this.widget.validate();
} catch (error) {
if (this.shouldRetry(error)) {
await this.retryPayment();
} else {
throw error;
}
}
}
shouldRetry(error) {
return (
error.type === 'NETWORK_ERROR' &&
this.retryCount < this.maxRetries
);
}
async retryPayment() {
this.retryCount++;
console.log(\`Retrying payment (attempt \${this.retryCount})\`);
await new Promise(resolve => setTimeout(resolve, 2000));
return this.processPayment();
}
}
- Check Network Status
function checkConnectivity() {
if (!navigator.onLine) {
showError('You are offline. Please check your internet connection.');
return false;
}
return true;
}
// Add network status listeners
window.addEventListener('online', () => {
hideError();
retryFailedPayments();
});
window.addEventListener('offline', () => {
showError('You are offline. Payment processing will resume when connected.');
});
Validation Issues
Symptoms:
- Fields show validation errors
ERROR
events
- Form submission blocked
Solutions:
- Debug Field Values
function debugFieldValues() {
const state = widget.getState();
Object.entries(state.fields).forEach(([fieldName, field]) => {
console.log(\`Field: \${fieldName}\`, {
value: field.value,
valid: field.valid,
error: field.error
});
});
}
- Custom Validation Rules
const config = {
fields: {
email: {
validation: {
pattern: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$',
message: 'Please enter a valid email address'
}
},
phone: {
validation: {
pattern: '^\\+?[1-9]\\d{1,14}$',
message: 'Please enter a valid phone number'
}
}
}
};
Browser Compatibility
Symptoms:
- Visual glitches
- Layout problems
- Style inconsistencies
Solutions:
- Check Browser Support
function checkBrowserSupport() {
const requirements = {
flexbox: 'flex' in document.documentElement.style,
grid: 'grid' in document.documentElement.style,
customProperties: CSS.supports('(--custom-property: value)'),
fetch: 'fetch' in window,
promise: 'Promise' in window
};
const unsupported = Object.entries(requirements)
.filter(([, supported]) => !supported)
.map(([feature]) => feature);
if (unsupported.length > 0) {
console.warn('Browser missing required features:', unsupported);
return false;
}
return true;
}
- Add Fallback Styles
const config = {
theme: {
css: {
// Modern browsers
'@supports (display: grid)': {
'.widget-container': {
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: '16px'
}
},
// Fallback for older browsers
'@supports not (display: grid)': {
'.widget-container': {
display: 'flex',
flexWrap: 'wrap'
},
'.field': {
flex: '0 0 calc(50% - 8px)',
marginRight: '16px'
}
}
}
}
};
Debug Mode
Enable debug mode to get detailed logging:
const widget = PaySightSDK.createWidget({
config: {
debug: true
},
onMessage: (message) => {
console.log('Widget Event:', {
type: message.type,
payload: message.payload,
timestamp: new Date(message.timestamp).toISOString()
});
}
});
Network Inspector
Monitor network requests:
class NetworkInspector {
constructor() {
this.requests = new Map();
}
startMonitoring() {
const originalFetch = window.fetch;
window.fetch = async (...args) => {
const requestId = Math.random().toString(36).slice(2);
const startTime = Date.now();
this.requests.set(requestId, {
url: args[0],
startTime,
status: 'pending'
});
try {
const response = await originalFetch(...args);
this.requests.set(requestId, {
...this.requests.get(requestId),
status: 'complete',
duration: Date.now() - startTime,
responseStatus: response.status
});
return response;
} catch (error) {
this.requests.set(requestId, {
...this.requests.get(requestId),
status: 'error',
duration: Date.now() - startTime,
error: error.message
});
throw error;
}
};
}
getRequestLog() {
return Array.from(this.requests.values());
}
}
State Inspector
Monitor widget state changes:
class StateInspector {
constructor(widget) {
this.widget = widget;
this.stateHistory = [];
}
startMonitoring() {
setInterval(() => {
const currentState = this.widget.getState();
this.stateHistory.push({
timestamp: Date.now(),
state: { ...currentState }
});
}, 1000);
}
getStateChanges() {
return this.stateHistory;
}
getDiff(index) {
if (index < 1) return null;
const previous = this.stateHistory[index - 1].state;
const current = this.stateHistory[index].state;
return {
timestamp: this.stateHistory[index].timestamp,
changes: this.diffObjects(previous, current)
};
}
diffObjects(obj1, obj2) {
const changes = {};
Object.keys({ ...obj1, ...obj2 }).forEach(key => {
if (JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])) {
changes[key] = {
from: obj1[key],
to: obj2[key]
};
}
});
return changes;
}
}
Next Steps