QR Code Payments: Making Crypto Transactions User-Friendly

QR codes have revolutionized cryptocurrency payments, making them as easy as scanning with a smartphone. This guide covers QR code payment implementation and best practices.

Why QR Codes for Crypto Payments?

User Experience Benefits

  • Simple: Just scan and pay
  • Fast: No manual address entry
  • Error-Free: Eliminates typos in addresses
  • Mobile-Friendly: Perfect for smartphone users
  • Familiar: Users already know how to scan QR codes

Business Benefits

  • Higher Conversion: Easier payments = more completed transactions
  • Reduced Errors: No incorrect addresses
  • Better UX: Professional payment experience
  • Mobile Optimization: Reach mobile-first customers

QR Code Standards

Payment URI Format

Cryptocurrency QR codes use URI schemes:

ethereum:0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb?value=1000000000000000000 bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa?amount=0.001

BIP-21 Standard

Bitcoin Improvement Proposal 21 defines QR code format:

bitcoin:ADDRESS?amount=AMOUNT&label=LABEL&message=MESSAGE

Generating QR Codes

JavaScript Implementation

const QRCode = require('qrcode');

async function generatePaymentQR(invoice) {
  const paymentURI = `ethereum:${invoice.depositAddress}?value=${invoice.amountWei}`;

  // Generate QR code as data URL
  const qrCodeDataURL = await QRCode.toDataURL(paymentURI, {
    width: 300,
    margin: 2,
    color: {
      dark: '#000000',
      light: '#FFFFFF'
    }
  });

  return qrCodeDataURL;
}

// Usage
const invoice = {
  depositAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
  amount: '1.0',
  amountWei: '1000000000000000000'
};

const qrCode = await generatePaymentQR(invoice);

React Component

import QRCode from 'qrcode.react';

function PaymentQRCode({ address, amount, currency }) {
  const paymentURI = `${currency}:${address}?amount=${amount}`;

  return (
    <div className="payment-qr">
      <QRCode
        value={paymentURI}
        size={256}
        level="H"
        includeMargin={true}
      />
      <p className="address">{address}</p>
      <p className="amount">{amount} {currency}</p>
    </div>
  );
}

Best Practices

1. Clear Visual Design

  • Large QR Code: Minimum 256x256 pixels
  • High Contrast: Black on white
  • Error Correction: Use level H for reliability
  • White Border: Include margin around code

2. Include Payment Details

Display alongside QR code:

  • Amount: Clearly show payment amount
  • Currency: Which cryptocurrency
  • Address: Full address (for verification)
  • Expiration: Time remaining

3. Mobile Optimization

function MobilePaymentQR({ invoice }) {
  return (
    <div className="mobile-payment">
      <div className="qr-container">
        <QRCode value={invoice.paymentURI} size={300} />
      </div>
      
      <div className="payment-details">
        <h3>Amount: {invoice.amount} {invoice.currency}</h3>
        <p className="address">{invoice.depositAddress}</p>
        <button onClick={() => copyAddress(invoice.depositAddress)}>
          Copy Address
        </button>
      </div>
      
      <div className="timer">
        <p>Expires in: {formatTime(invoice.expiresIn)}</p>
      </div>
    </div>
  );
}

4. Deep Linking

Enable direct wallet opening:

function generateDeepLink(address, amount, currency) {
  // MetaMask
  const metamaskLink = `https://metamask.app.link/dapp/pay?address=${address}&amount=${amount}`;

  // Trust Wallet
  const trustLink = `trust://wc?uri=${encodeURIComponent(paymentURI)}`;

  // Generic
  return {
    metamask: metamaskLink,
    trust: trustLink,
    generic: paymentURI
  };
}

Payment Flow with QR Codes

Step 1: Generate Invoice

async function createInvoiceWithQR(amount, currency) {
  // Create invoice
  const invoice = await paymentGateway.createInvoice({
    amount,
    currency
  });

  // Generate QR code
  const qrCode = await generatePaymentQR(invoice);

  return {
    ...invoice,
    qrCode
  };
}

Step 2: Display QR Code

function PaymentPage({ invoice }) {
  return (
    <div className="payment-page">
      <h2>Scan to Pay</h2>
      
      <div className="qr-section">
        <img src={invoice.qrCode} alt="Payment QR Code" />
        <p>Scan with your crypto wallet</p>
      </div>
      
      <div className="details">
        <p><strong>Amount:</strong> {invoice.amount} {invoice.currency}</p>
        <p><strong>Address:</strong> {invoice.depositAddress}</p>
        <button onClick={() => copyToClipboard(invoice.depositAddress)}>
          Copy Address
        </button>
      </div>
      
      <PaymentStatus invoiceId={invoice.id} />
    </div>
  );
}

Step 3: Monitor Payment

function PaymentStatus({ invoiceId }) {
  const [status, setStatus] = useState('PENDING');

  useEffect(() => {
    const interval = setInterval(async () => {
      const invoice = await checkInvoiceStatus(invoiceId);
      setStatus(invoice.status);
      
      if (invoice.status === 'CONFIRMED') {
        clearInterval(interval);
        // Redirect to success page
      }
    }, 3000);

    return () => clearInterval(interval);
  }, [invoiceId]);

  return (
    <div className="status">
      <p>Status: {status}</p>
      {status === 'PENDING' && <p>Waiting for payment...</p>}
      {status === 'DETECTED' && <p>Payment detected, confirming...</p>}
      {status === 'CONFIRMED' && <p>Payment confirmed!</p>}
    </div>
  );
}

Advanced Features

Multi-Currency QR Codes

Support multiple cryptocurrencies:

function generateMultiCurrencyQR(invoice) {
  const qrCodes = {
    USDT: generateQR('ethereum', invoice.usdtAddress, invoice.amount),
    BTC: generateQR('bitcoin', invoice.btcAddress, invoice.amount),
    ETH: generateQR('ethereum', invoice.ethAddress, invoice.amount)
  };

  return qrCodes;
}

Dynamic QR Codes

Update QR code based on payment status:

function DynamicQR({ invoice }) {
  const [qrValue, setQrValue] = useState(invoice.paymentURI);

  useEffect(() => {
    if (invoice.status === 'PARTIALLY_PAID') {
      const remaining = invoice.amountExpected - invoice.amountReceived;
      setQrValue(generateURI(invoice.address, remaining));
    }
  }, [invoice.status]);

  return <QRCode value={qrValue} />;
}

Testing QR Codes

Test Checklist

  • QR code scans correctly
  • Amount is correct
  • Address is correct
  • Works on iOS and Android
  • Works with major wallets
  • Error correction works
  • Mobile responsive

Testing Tools

  • QR Code Scanner Apps: Test on real devices
  • Online Scanners: Verify QR content
  • Wallet Apps: Test actual payment flow

Common Issues and Solutions

QR Code Not Scanning

Solutions:

  • Increase QR code size
  • Improve contrast
  • Add error correction
  • Ensure good lighting

Wrong Amount

Solution: Always verify amount in QR code URI matches displayed amount.

Address Mismatch

Solution: Display full address alongside QR code for verification.

Conclusion

QR codes make cryptocurrency payments as easy as traditional mobile payments. Implementing them correctly significantly improves user experience and conversion rates.

Start using QR code payments with FromChain and make crypto payments effortless!