The preo-transaction-status custom element provides a seamless way to display transaction status after payment processing. It automatically polls for transaction updates and emits events that you can use to display appropriate UI to your users.
Overview
When customers complete a payment through Preo checkout, they are redirected to a transaction status page. The preo-transaction-status element handles:
Automatic polling with exponential backoff
Provider status verification
Event emission for different transaction states
Retry logic with smart fallbacks
Basic Usage
< preo-transaction-status transaction-id = "tr_123456789" />
Required Attributes
transaction-id : The unique transaction identifier (typically from URL parameters like ?tid=, ?invoice=, or ?s=)
Optional Attributes
sdk-id : Your Preo SDK identifier in the format environment:cluster:tenant:event. When provided, enables:
Analytics tracking through the Preo Analytics component
Event-specific configuration
Custom API endpoints
Note : Starting from version 0.6.0, sdk-id is optional. If not provided, the component will use the default Preo API endpoint.
Events
The component emits the following events that you can listen to:
onTransactionStatusChange
Fired whenever the transaction status changes or is checked.
document. addEventListener ( 'onTransactionStatusChange' , ( event ) => {
const { transaction , isWaitingForFinalConfirmation } = event.detail[ 0 ];
switch (transaction.status) {
case 'pending' :
case 'started' :
// Show "processing" UI
break ;
case 'provider_confirmed' :
// Show "almost there" UI
break ;
case 'completed' :
// Show success UI
break ;
case 'fail' :
// Show error UI
break ;
}
});
onTransactionCompleted
Fired only when the transaction is successfully completed. This is emitted through the global event system.
window. addEventListener ( 'onTransactionCompleted' , ( event ) => {
const { transaction , user , token } = event.detail;
// Handle successful transaction
// Save user data, redirect, etc.
});
Transaction Statuses
pending/started : Transaction is being processed
provider_confirmed : Payment provider confirmed the payment, but backend is still processing
completed : Transaction successfully completed
fail : Transaction failed or couldn't be verified
Implementation Examples
Nuxt 3
Add the script to nuxt.config.ts:
export default defineNuxtConfig ({
app: {
head: {
script: [{
src: 'https://cdn.jsdelivr.net/npm/@preo-live/components@latest/dist/components.umd.js' ,
defer: true
}]
}
},
vue: {
compilerOptions: {
isCustomElement : ( tag ) => tag. startsWith ( 'preo-' )
}
}
})
Create a transaction status page:
<template>
<div class="transaction-status">
<div v-if="status === 'pending' || status === 'started'">
<h2>Processing your order...</h2>
<p>We're verifying your payment details...</p>
</div>
<div v-else-if="status === 'provider_confirmed'">
<h2>Almost there!</h2>
<p>Your payment has been confirmed and we're finalizing your order.</p>
</div>
<div v-else-if="status === 'completed'">
<h2>Thank you for your purchase!</h2>
<p>Your order has been confirmed.</p>
</div>
<div v-else-if="status === 'fail'">
<h2>Something went wrong</h2>
<p>We're having trouble completing your order. Please contact support.</p>
</div>
<preo-transaction-status
:transaction-id="transactionId"
@onTransactionStatusChange="handleStatusChange"
/>
</div>
</template>
<script setup>
const route = useRoute()
const status = ref('pending')
const transactionId = computed(() =>
route.query.tid || route.query.invoice || route.query.s || ''
)
const handleStatusChange = (event) => {
const data = event.detail[0]
if (data.transaction) {
status.value = data.transaction.status
// Handle completed transactions
if (data.transaction.status === 'completed' && data.user) {
// Save user data, update auth state, etc.
console.log('Transaction completed', data)
}
}
}
onMounted(() => {
document.addEventListener('onTransactionStatusChange', handleStatusChange)
})
onUnmounted(() => {
document.removeEventListener('onTransactionStatusChange', handleStatusChange)
})
</script>
Next.js
Add the script to your layout or page:
import Script from 'next/script'
export default function TransactionLayout ({ children }) {
return (
<>
< Script
src = "https://cdn.jsdelivr.net/npm/@preo-live/components@latest/dist/components.umd.js"
strategy = "afterInteractive"
/>
{ children }
</>
)
}
Create a transaction status page:
'use client'
import { useSearchParams } from 'next/navigation'
import { useEffect, useState, useRef } from 'react'
declare global {
namespace JSX {
interface IntrinsicElements {
'preo-transaction-status' : React . DetailedHTMLProps <
React . HTMLAttributes < HTMLElement > & {
'transaction-id' : string
'sdk-id' ?: string
},
HTMLElement
>
}
}
}
export default function TransactionStatusPage () {
const searchParams = useSearchParams ()
const [ status , setStatus ] = useState ( 'pending' )
const elementRef = useRef ( null )
const transactionId = searchParams. get ( 'tid' ) ||
searchParams. get ( 'invoice' ) ||
searchParams. get ( 's' ) || ''
useEffect (() => {
const handleStatusChange = ( event : CustomEvent ) => {
const data = event.detail[ 0 ]
if (data.transaction) {
setStatus (data.transaction.status)
if (data.transaction.status === 'completed' ) {
// Handle successful transaction
console. log ( 'Transaction completed' , data)
}
}
}
document. addEventListener ( 'onTransactionStatusChange' , handleStatusChange)
return () => {
document. removeEventListener ( 'onTransactionStatusChange' , handleStatusChange)
}
}, [])
return (
< div className = "transaction-status" >
{( status === ' pending ' || status === ' started ') && (
< div >
< h2 > Processing your order ...</ h2 >
< p > We ' re verifying your payment details ...</ p >
</ div >
)}
{ status === ' provider_confirmed ' && (
< div >
< h2 > Almost there !</ h2 >
< p > Your payment has been confirmed and we ' re finalizing your order .</ p >
</ div >
)}
{ status === ' completed ' && (
< div >
< h2 > Thank you for your purchase !</ h2 >
< p > Your order has been confirmed .</ p >
</ div >
)}
{ status === ' fail ' && (
< div >
< h2 > Something went wrong </ h2 >
< p > We ' re having trouble completing your order . Please contact support .</ p >
</ div >
)}
< preo - transaction - status
ref = {elementRef}
transaction - id = {transactionId}
/>
</ div >
)
}
Advanced Configuration
With SDK ID (Full Analytics)
When you need analytics tracking and event-specific configuration:
< preo-transaction-status
transaction-id = "tr_123456789"
sdk-id = "prod:eu:tenant:event" >
</ preo-transaction-status >
Custom Retry Logic
The component uses the following retry strategy by default:
5 retry attempts with delays: 5s, 7s, 10s, 12s, 10s
After 5 failed attempts, checks with the payment provider directly
If provider confirms but backend hasn't received it (HTTP 202), waits 10s for final confirmation
Handling Analytics
The component automatically emits analytics events when transactions are completed. To integrate with your analytics:
window. addEventListener ( 'onTransactionCompleted' , ( event ) => {
const { transaction , user , transactionId } = event.detail;
// Google Analytics
gtag ( 'event' , 'purchase' , {
transaction_id: transactionId,
value: transaction.total,
currency: transaction.currency
});
// Facebook Pixel
fbq ( 'track' , 'Purchase' , {
value: transaction.total,
currency: transaction.currency
});
// Google Tag Manager
dataLayer. push ({
'event' : 'purchase' ,
'ecommerce' : {
'transaction_id' : transactionId,
'value' : transaction.total,
'currency' : transaction.currency
}
});
});
Troubleshooting
Component Not Working
Ensure the Preo components script is loaded before the element is used
Check that custom elements are allowed in your framework (see framework-specific configs above)
Verify the transaction-id is correct and not empty
Events Not Firing
Make sure you're listening to the correct event names
Remember that onTransactionStatusChange is emitted on document, while onTransactionCompleted is on window
Check browser console for any errors
Status Stuck on "Processing"
This usually means:
The transaction ID is invalid
Network issues preventing API calls
The transaction is genuinely taking longer to process
Version Compatibility
Requires @preo-live/components version 0.5.0 or higher
sdk-id is optional starting from version 0.6.0
Works with all modern browsers that support Custom Elements
For older browsers, include the Custom Elements polyfill
Last modified on January 29, 2026