EU
MiCA licensed Learn more →
Widget

Web Widget

Web Widget enables your users to buy or sell crypto from your app or website.

AhoraCrypto Web Widget is a developer integration to onboard global users from fiat to crypto and back, using credit cards, debit, and local payment methods.

  • Accept credit card, debit card, bank transfer, Apple Pay and Google Pay
  • +40 cryptocurrencies and tokens supported
  • More than 162 countries and territories supported
  • Continuously adding new currencies, blockchains, digital assets and protocols
AhoraCrypto Web Widget

See it in action at https://webwidget.ahoracrypto.com

Installation

Using the JavaScript Widget

Include the script in your HTML page (at header section):

html
<script src="https://webwidget.ahoracrypto.com/webwidget.js"></script>

Create a container element:

html
<div id="crypto-widget-container"></div>

Initialize the widget:

html
<script>
    let widget = window.AhoraCrypto.renderWebwidget({
        containerId: 'crypto-widget-container', // Only required parameter
        language: 'en',
        cryptoCurrency: 'btc',
        fiatCurrency: 'usd'
    });
</script>

Interact with the widget (e.g. set a wallet address):

html
<script>
...
    // Wait for the widget to be ready before interacting with it
    widget.onReady(() => {
        widget.setWalletAddress('0x1234567890123456789012345678901234567890');
    }
...
</script>

Try it by yourself at https://webwidget.ahoracrypto.com

Configuration Parameters

All parameters are optional except for containerId. The widget will use default values for any parameters not explicitly provided.

ParameterTypeRequiredDescription
containerIdstringYesID of the HTML element where the widget will be rendered
languagestringNoLanguage for the widget (e.g., 'en', 'es'). If not specified or set to 'auto', will use browser default
cryptoCurrencystringNoThe default cryptocurrency to select (e.g., 'BTC')
fiatCurrencystringNoThe default fiat currency to select (e.g., 'USD', 'EUR'). If not specified or set to 'auto', will detect user's region
logoUrlstringNoURL to a custom logo image to display at the top of the widget
backgroundColorstringNoBackground color for the widget (HEX without #)
buttonColorstringNoColor for buttons (HEX without #)
borderRadiusnumberNoWidget border radius (in pixels)
borderWithShadowbooleanNoWhether to show a shadow around the widget border
themestringNoThe theme for the widget ('light', 'dark', or 'auto'). If set to 'auto', it will follow the user's system settings
iframeWidthnumberNoWidth of the iframe (default: 416px)
iframeHeightnumberNoHeight of the iframe (default: 510px)
paymentIntentIdstringNoID of a Payment Intent created from your backend. The widget opens prefilled with that Payment Intent and pays it at the end, without creating a new order (see Payment Intent flow)
referralstringNoReferral code or ID for tracking and attribution purposes. This allows you to identify transactions originating from your integration
cryptosstringNoComma-separated list of cryptocurrency symbols to display (e.g., 'ETH,BTC,USDC'). If not specified, all available cryptocurrencies will be shown
defaultNetworkstringNoDefault network to be selected (e.g., 'BSC', 'ETH'). If specified, this network will be selected by default

Try it by yourself at https://webwidget.ahoracrypto.com

Payment Intent flow

Instead of letting the user choose what to buy, you can create a Payment Intent from your backend and open the widget to complete it, by passing its ID as paymentIntentId:

javascript
// 1. From your backend (never expose your API key in the browser), create the
//    Payment Intent and pass its id to the page:
//    POST https://api.ahoracrypto.com/payment/intent  ->  { "id": "3f2a...", ... }

// 2. Open the widget for that Payment Intent
let widget = window.AhoraCrypto.renderWebwidget({
    containerId: 'widget-container',
    paymentIntentId: '3f2a...'
});

When opened for a Payment Intent, the widget behaves as follows:

  • The operation comes prefilled. The widget starts with its usual screens, already filled in with the Payment Intent's cryptocurrency, fiat currency, amount, destination wallet and network. What is paid at the end is always the Payment Intent as you created it.
  • The user is signed in automatically. As soon as the widget opens, it signs in the Payment Intent's user, replacing any session open in the browser. If that user was created by your store (through one of your Payment Intents, for example identified by externalUserId), the session is a regular one. Otherwise, for instance if they already had an AhoraCrypto account, the session only allows completing this Payment Intent.
  • Only the missing steps are shown. After the prefilled screens, the user goes straight to payment when everything is in place. If not, the widget first asks for what is missing: an email when the user has none (a Payment Intent created with externalUserId and no email), and the KYC verification while it is still pending.
  • Returning users go faster. A user identified again with the same externalUserId keeps their verified email and KYC, so later Payment Intents usually go straight to payment.
  • The payment settles the Payment Intent. The widget pays the Payment Intent's own order, it never creates a separate one. Its status, ipnUrl notifications and order number work exactly as described in the Payment Intent API.
  • Payment Intents that can no longer be paid (already paid, expired or cancelled) show an error instead of the payment screen.

Widget Controller Methods

The renderWebwidget function returns a controller object that provides methods to interact with the widget:

MethodDescriptionParameters
setWalletAddressSets a wallet address in the widgetwalletAddress (string): The crypto wallet address to use
setPaymentIntentIdUpdates the payment intent ID in the widget. To open the widget for a Payment Intent, pass paymentIntentId to renderWebwidget instead (see Payment Intent flow)paymentIntentId (string): The payment intent ID to use
sendSignedMessageSends a signed message to the widgetsignature (string): The signed message. address (string): The address that signed the message. messageHash (string, optional): Hash of the original message
requestMessageToSignRequests a message to sign from the widgetNone
connectWeb3WalletConnects a Web3 wallet to the widgetprovider (object): The Web3 provider (e.g., from MetaMask). accountAddress (string): Current wallet address. chainId (number): Current blockchain network ID
onReadyRegisters a callback function to be executed when the widget is fully loadedcallback (function): Function to execute when ready
readyReturns a Promise that resolves when the widget is fully loadedNone
isReadyReturns whether the widget is fully loadedNone

Ready State Handling

It's important to wait for the widget to be fully loaded before interacting with it. There are three ways to do this:

1. Using the callback approach:

javascript
let widget = window.AhoraCrypto.renderWebwidget({
    containerId: 'widget-container'
});

widget.onReady(() => {
    console.log('Widget is now ready!');
    widget.setWalletAddress('0x1234567890123456789012345678901234567890');
});

2. Using the Promise-based approach with async/await:

javascript
async function initWidget() {
    const widget = window.AhoraCrypto.renderWebwidget({
        containerId: 'widget-container'
    });

    // Wait for the widget to be ready
    await widget.ready();

    console.log('Widget is ready!');
    widget.setWalletAddress('0x1234567890123456789012345678901234567890');
}

initWidget();

3. Checking the ready state:

javascript
const widget = window.AhoraCrypto.renderWebwidget({
    containerId: 'widget-container'
});

// Poll the ready state (not recommended, use onReady or ready() instead)
const checkReady = setInterval(() => {
    if (widget.isReady()) {
        console.log('Widget is ready!');
        widget.setWalletAddress('0x1234567890123456789012345678901234567890');
        clearInterval(checkReady);
    }
}, 100);

Examples

Example of using widget methods

javascript
// Initialize the widget and get the controller
let widget = window.AhoraCrypto.renderWebwidget({
    containerId: 'widget-container',
    // other parameters...
});

// Wait for the widget to be ready before interacting with it
widget.onReady(() => {
    // Set a wallet address
    widget.setWalletAddress('0x1234567890123456789012345678901234567890');

    // Set a payment intent ID
    widget.setPaymentIntentId('pi_3N5555555555555555555555');
});

Web3 Wallet Integration Example

javascript
// Initialize the widget
let widget = window.AhoraCrypto.renderWebwidget({
    containerId: 'widget-container',
    cryptoCurrency: 'eth'
});

// Connect to MetaMask or other Web3 wallet
async function connectWallet() {
    if (window.ethereum) {
        try {
            // Request account access
            const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
            const chainId = await window.ethereum.request({ method: 'eth_chainId' });

            // Wait for the widget to be ready
            await widget.ready();

            // Connect the wallet to the widget
            widget.connectWeb3Wallet(
                window.ethereum,             // Provider
                accounts[0],                 // Current account address
                parseInt(chainId, 16)        // Current chain ID
            );

            console.log('Wallet connected:', accounts[0]);
        } catch (error) {
            console.error('Error connecting wallet:', error);
        }
    } else {
        console.error('Web3 provider not found. Please install MetaMask or another wallet');
    }
}

// Example function to sign a message
async function signMessage(message) {
    if (window.ethereum) {
        try {
            const accounts = await window.ethereum.request({ method: 'eth_accounts' });
            if (accounts.length === 0) {
                alert('Please connect your wallet first');
                return;
            }

            // Ensure widget is ready
            await widget.ready();

            // Get the message to sign from the widget
            widget.requestMessageToSign();

            // Set up listener for the message from the widget
            window.addEventListener('message', async (event) => {
                if (event.data && event.data.type === 'MESSAGE_TO_SIGN') {
                    const messageToSign = event.data.message || message;

                    // Sign the message with the wallet
                    const signature = await window.ethereum.request({
                        method: 'personal_sign',
                        params: [messageToSign, accounts[0]]
                    });

                    // Send the signed message back to the widget
                    widget.sendSignedMessage(signature, accounts[0], Web3.utils.keccak256(messageToSign));
                }
            }, { once: true }); // Only handle this once
        } catch (error) {
            console.error('Error signing message:', error);
        }
    }
}

// Attach the connect function to a button
document.getElementById('connect-wallet-btn').addEventListener('click', connectWallet);

Customization example

javascript
let widget = window.AhoraCrypto.renderWebwidget({
    containerId: 'widget-container', // Only required parameter
    language: 'en',
    cryptoCurrency: 'btc',
    fiatCurrency: 'usd',
    logoUrl: 'https://ahoracrypto.com/en/assets/images/logo.png',
    backgroundColor: 'FCE8D5',
    buttonColor: 'F7931A',
    borderRadius: 24,
    borderWithShadow: true,
    theme: 'light',
    iframeWidth: 416,
    iframeHeight: 510,
    paymentIntentId: 'pi_3N5555555555555555555555',
    referral: 'partner123', // Referral code for tracking and attribution
    cryptos: 'ETH,BTC,USDC',  // Only show these cryptos
    defaultNetwork: 'BSC'    // Set BSC as default network
});

Real-world examples

Examples from other websites:

from GT3 dapp
from GT3 dapp
HashPack
from HashPack Wallet