Skrill JS Live Demo
Interactive example of the Skrill JS SDK integration.
Result
Loading...
Live Editor
function SkrillJsPaymentDemo() { const MERCHANT_ID = 0; // Change this to your actual Merchant ID (number) for production use const SESSION_ID = ''; // Change this to generated Session ID const [sdkStatus, setSdkStatus] = React.useState('idle'); const [fieldsInitialized, setFieldsInitialized] = React.useState(false); const [paymentStatus, setPaymentStatus] = React.useState(''); const [instance, setInstance] = React.useState(null); const [cardBrand, setCardBrand] = React.useState(''); const [unsupportedCardBrand, setUnsupportedCardBrand] = React.useState(''); const [fieldsValid, setFieldsValid] = React.useState(false); const [fieldEvents, setFieldEvents] = React.useState([]); const [isProcessingPayment, setIsProcessingPayment] = React.useState(false); const [fxConversionAgreement, setFxConversionAgreement] = React.useState(null); const [sdkLanguage, setSdkLanguage] = React.useState('EN'); const sdkLoaded = React.useMemo(() => sdkStatus === 'loaded', [sdkStatus]); const hasUnsupportedCardBrand = React.useMemo(() => unsupportedCardBrand && unsupportedCardBrand === cardBrand, [unsupportedCardBrand, cardBrand]); // Load Skrill JS SDK React.useEffect(() => { if (!window.skrill) { const script = document.createElement('script'); script.src = 'https://pay.skrill.com/skrill-js/skrill.min.js'; script.onload = () => { setSdkStatus('loaded') setPaymentStatus('✅ Skrill JS SDK loaded successfully'); }; script.onerror = () => { setSdkStatus('failed') setPaymentStatus('❌ Failed to load Skrill JS SDK'); }; setSdkStatus('loading') document.head.appendChild(script); } else if (window.skrill) { setSdkStatus('loaded') setPaymentStatus('✅ Skrill JS SDK already loaded'); } }, []); // Handle language changes React.useEffect(() => { if (sdkLanguage && instance) { // Note: setLanguage() only changes the SDK's internal language settings (e.g. VISA consent text). // It does not change the parent application's language. instance.setLanguage(sdkLanguage).then(() => setPaymentStatus(`🌍 SDK Language changed to: ${sdkLanguage}`)) } }, [sdkLanguage, instance]); const initializeFields = async () => { try { setPaymentStatus('🔄 Initializing payment fields...'); // Initialize Skrill JS fields const skrillJsInstance = await window.skrill.fields.setup( parseInt(MERCHANT_ID), SESSION_ID, { fields: { cardNumber: { selector: '#card-number-field', placeholder: '1234 5678 9012 3456' }, cvv: { selector: '#cvv-field', placeholder: '123' }, expiryDate: { selector: '#expiry-field', placeholder: 'MM/YY' }, cardHolder: { selector: '#cardholder-field', placeholder: 'John Doe' }, email: { selector: '#email-field', placeholder: 'john.doe@example.com' }, consent: { selector: '#consent-field' } }, style: { input: { 'font-family': 'Arial, sans-serif', 'font-weight': 'normal', 'font-size': '16px', color: '#333333', padding: '0 12px' }, '.valid': { color: '#157a38' }, '.invalid': { color: '#B0460C' } }, initializationTimeout: 20000 } ); skrillJsInstance.cardBrandRecognition((instance, event) => { setCardBrand(instance.getCardBrand()); }); skrillJsInstance.unsupportedCardBrand((instance, event) => { setUnsupportedCardBrand(event.data.cardBrand); }); const setupFieldsEventListeners = (skrillJsInstance) => { const availableFields = ['cardNumber', 'cvv', 'expiryDate', 'cardHolder']; // Check if email field is available in the skrillJsInstance before subscribing to events if (skrillJsInstance.fields.email) { availableFields.push('email'); } // Check if consent field is available in the skrillJsInstance before subscribing to events if (skrillJsInstance.fields.consent) { availableFields.push('consent'); } const handleFieldEvent = (instance, event, error) => { setFieldsValid(instance.areAllFieldsValid()); const eventLog = { timestamp: new Date().toLocaleTimeString(), event: event, error: error || null }; setFieldEvents(prev => [eventLog, ...prev.slice(0, 19)]); }; skrillJsInstance.fields(availableFields.join(' ')) .on('focus blur valid invalid fieldValueChange', handleFieldEvent); }; setupFieldsEventListeners(skrillJsInstance); setInstance(skrillJsInstance); setFieldsInitialized(true); setPaymentStatus({ type: 'success', message: '✅ Payment fields initialized successfully', response: skrillJsInstance }); } catch (error) { setPaymentStatus({ type: 'error', message: `❌ Failed to initialize: ${error.message || error}`, response: error }); } }; const processPayment = async () => { if (!instance.areAllFieldsValid()) { setPaymentStatus('❌ Please complete all required fields'); return; } try { setIsProcessingPayment(true); setPaymentStatus('🔄 Processing payment...'); const response = await instance.pay( { fxConversionAccepted: !!fxConversionAgreement?.accepted } ); switch (response.status) { case 'PROCESSED': setPaymentStatus({ type: 'success', message: '✅ Payment successful!', response }); setFxConversionAgreement(null); break; case 'FAILED': setPaymentStatus({ type: 'error', message: '❌ Payment failed', response }); setFxConversionAgreement(null); break; case 'FX_CONVERSION_NOTIFICATION': setFxConversionAgreement({ processingAmount: response.processingAmount, processingCurrency: response.processingCurrency, accepted: false }); setPaymentStatus({ type: 'info', message: '💱 FX conversion agreement required', response }); break; default: setPaymentStatus({ type: 'info', message: `ℹ️ Payment status: ${response.status}`, response }); } } catch (error) { setPaymentStatus({ type: 'error', message: `❌ Payment error: ${error.displayMessage || error.message || error}`, response: error }); setFxConversionAgreement(null); } finally { setIsProcessingPayment(false); } }; const focusField = (fieldName) => { instance.focusField(fieldName); setPaymentStatus(`🎯 Focus manually changed to ${fieldName}`); }; const resetFields = () => { instance.resetCardDetails(); setPaymentStatus('🔄 Card details reset'); setFxConversionAgreement(null); }; return ( <div style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}> <h2>Pay with card</h2> <SdkLoadingSpinner sdkStatus={sdkStatus} /> <div> {!fieldsInitialized && ( <> <InitializePaymentFieldsButton onClick={initializeFields} disabled={!sdkLoaded || !SESSION_ID || !MERCHANT_ID} /> {sdkLoaded && (!MERCHANT_ID || !SESSION_ID) && ( <InfoBox> Make sure to set valid MERCHANT_ID and SESSION_ID values below before initializing. </InfoBox> )} </> )} {fieldsInitialized && ( <div style={{ display: 'flex', alignItems: 'flex-end' }}> <ResetCardDetailsButton onClick={resetFields} /> <LanguageSelector sdkLanguage={sdkLanguage} setSdkLanguage={setSdkLanguage} /> </div> )} </div> {/* Payment Fields Section */} <div style={{ backgroundColor: '#ffffff', padding: '20px', borderRadius: '8px', marginBottom: '20px', border: '2px solid #e1e5e9' }} // IMPORTANT: Use 'hidden' instead of conditional rendering to keep DOM placeholders available. // Skrill JS SDK requires all field containers to exist in the DOM during the whole process. // Conditional rendering (&&) would remove elements and cause initialization failures. hidden={!fieldsInitialized} > <h3>Card Details</h3> {/* Card Number - Full width */} <div style={{ marginBottom: '15px' }}> <label style={{ display: 'block', marginBottom: '8px', fontWeight: 'bold', color: '#495057' }} onClick={() => focusField('cardNumber')} > Card Number: </label> <div id="card-number-field" style={{ height: '44px', border: '1px solid #ccc', borderRadius: '4px', backgroundColor: '#fff' }}></div> </div> {/* Expiry Date and CVV - Same row */} <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '15px', marginBottom: '15px' }}> <div> <label style={{ display: 'block', marginBottom: '8px', fontWeight: 'bold', color: '#495057' }} onClick={() => focusField('expiryDate')} > Expiry Date: </label> <div id="expiry-field" style={{ height: '44px', border: '1px solid #ccc', borderRadius: '4px', backgroundColor: '#fff' }}></div> </div> <div> <label style={{ display: 'block', marginBottom: '8px', fontWeight: 'bold', color: '#495057' }} onClick={() => focusField('cvv')} > CVV: </label> <div id="cvv-field" style={{ height: '44px', border: '1px solid #ccc', borderRadius: '4px', backgroundColor: '#fff' }}></div> </div> </div> {/* Cardholder Name - Full width */} <div style={{ marginBottom: '15px' }}> <label style={{ display: 'block', marginBottom: '8px', fontWeight: 'bold', color: '#495057' }} onClick={() => focusField('cardHolder')} > Cardholder Name: </label> <div id="cardholder-field" style={{ height: '44px', border: '1px solid #ccc', borderRadius: '4px', backgroundColor: '#fff' }}></div> </div> {/* Email - Full width */} <div style={{ marginBottom: '15px' }} hidden={!instance?.fields.email}> <label style={{ display: 'block', marginBottom: '8px', fontWeight: 'bold', color: '#495057' }} onClick={() => focusField('email')} > Email: </label> <div id="email-field" style={{ height: '44px', border: '1px solid #ccc', borderRadius: '4px', backgroundColor: '#fff' }}></div> </div> {/* Consent - Full width, no label, no borders */} <div style={{ marginBottom: '20px' }} hidden={!instance?.fields.consent}> <div id="consent-field" style={{ height: '44px' }}></div> </div> <CardBrandInfo cardBrand={cardBrand} /> {hasUnsupportedCardBrand && ( <WarningBox> The detected card brand ({cardBrand}) is not supported. Please use a supported card type. </WarningBox> )} <FxConversionAgreement fxConversionAgreement={fxConversionAgreement} onChange={setFxConversionAgreement} /> <PayButton onClick={processPayment} disabled={!fieldsValid || isProcessingPayment} /> </div> <PaymentStatus paymentStatus={paymentStatus} /> <FieldEvents fieldEvents={fieldEvents} fieldsInitialized={fieldsInitialized} /> </div> ); }
Getting Started
To integrate Skrill JS SDK in your application:
- Include the SDK: Load the Skrill JS script in your HTML
- Configure Fields: Set up hosted fields with your merchant ID and session ID
- Handle Events: Listen for validation, card brand detection, and payment events
- Process Payments: Use the
pay()
method to securely process payments
The demo above shows a complete integration where different scenarios can be tried and experimented with.