• Welcome
  • Integration
  • API
Preo
  • Homepage
  • About
Apps
  • Dashboard
  • App Store
  • Google Play
Social
  • LinkedIn

© 2026 Preo ApS

Introduction
Web Component
    PreviewConfiguration OptionsCustom transaction status page
Frameworks
    NuxtNext.js
Web Component

Custom transaction status page

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

Code
<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.

Code
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.

Code
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

  1. Add the script to nuxt.config.ts:
Code
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-') } } })
  1. Create a transaction status page:
Code
<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

  1. Add the script to your layout or page:
Code
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} </> ) }
  1. Create a transaction status page:
Code
'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:

Code
<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:

Code
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

  1. Ensure the Preo components script is loaded before the element is used
  2. Check that custom elements are allowed in your framework (see framework-specific configs above)
  3. Verify the transaction-id is correct and not empty

Events Not Firing

  1. Make sure you're listening to the correct event names
  2. Remember that onTransactionStatusChange is emitted on document, while onTransactionCompleted is on window
  3. 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
Configuration OptionsNuxt
On this page
  • Overview
  • Basic Usage
  • Required Attributes
  • Optional Attributes
  • Events
    • onTransactionStatusChange
    • onTransactionCompleted
  • Transaction Statuses
  • Implementation Examples
    • Nuxt 3
    • Next.js
  • Advanced Configuration
    • With SDK ID (Full Analytics)
    • Custom Retry Logic
    • Handling Analytics
  • Troubleshooting
    • Component Not Working
    • Events Not Firing
    • Status Stuck on "Processing"
  • Version Compatibility
Javascript
Javascript
TypeScript
TypeScript
TypeScript
Javascript