HTML5 APIs Guide

HTML5 introduced numerous JavaScript APIs that enable powerful web applications with features previously available only in native applications. This guide covers the most important HTML5 APIs and how to use them.

1. Canvas API

The Canvas API provides a means for drawing graphics via JavaScript on a <canvas> element. It can be used for animations, game graphics, data visualization, photo manipulation, and real-time video processing.

<!-- Canvas element in HTML --> <canvas id="myCanvas" width="300" height="150"> Your browser does not support the canvas element. </canvas> <script> // JavaScript to draw on the canvas const canvas = document.getElementById('myCanvas'); const ctx = canvas.getContext('2d'); // Set fill and stroke styles ctx.fillStyle = 'red'; ctx.strokeStyle = 'black'; // Draw a rectangle ctx.fillRect(25, 25, 100, 100); ctx.clearRect(45, 45, 60, 60); ctx.strokeRect(50, 50, 50, 50); // Draw a path ctx.beginPath(); ctx.moveTo(150, 25); ctx.lineTo(250, 75); ctx.lineTo(150, 125); ctx.fill(); </script>
Your browser does not support the canvas element.

Canvas 2D API Methods

Category Common Methods Description
Rectangles fillRect(), strokeRect(), clearRect() Draw filled, outlined, or clear rectangles
Paths beginPath(), closePath(), moveTo(), lineTo(), arc(), arcTo(), bezierCurveTo() Create and draw paths with lines and curves
Path Operations fill(), stroke(), clip() Fill, stroke, or create a clipping region from the current path
Text fillText(), strokeText(), measureText() Draw and measure text on the canvas
Images drawImage() Draw images, video frames, or other canvases
Pixel Manipulation createImageData(), getImageData(), putImageData() Manipulate individual pixels in the canvas
Transformations scale(), rotate(), translate(), transform() Apply transformations to the canvas context
Canvas vs. SVG:
  • Canvas: Pixel-based, better for complex scenes with many objects, animations, or pixel manipulation
  • SVG: Vector-based, better for scalable graphics, accessibility, and when DOM interaction is needed
  • Canvas requires JavaScript to draw and doesn't maintain a scene graph (what you draw is forgotten after rendering)
  • SVG elements remain in the DOM and can be styled with CSS and manipulated directly

2. Web Storage API

The Web Storage API provides mechanisms for websites to store key-value pairs locally in the user's browser, persisting beyond page refresh and between browser sessions:

<!-- Local Storage (persists indefinitely) --> <script> // Storing data localStorage.setItem('username', 'JohnDoe'); localStorage.setItem('preferences', JSON.stringify({ theme: 'dark', fontSize: 16, notifications: true })); // Retrieving data const username = localStorage.getItem('username'); const preferences = JSON.parse(localStorage.getItem('preferences')); // Removing data localStorage.removeItem('username'); // Clearing all data localStorage.clear(); </script> <!-- Session Storage (persists for the session) --> <script> // Same API as localStorage, but limited to the current session sessionStorage.setItem('temporaryToken', 'abc123'); const token = sessionStorage.getItem('temporaryToken'); </script>

Local Storage vs. Session Storage

Feature localStorage sessionStorage
Persistence Until explicitly cleared by code or user Until the browser tab/window is closed
Scope Shared across all tabs/windows from the same origin Limited to the tab/window that created it
Storage Limit ~5MB per origin (varies by browser) ~5MB per origin (varies by browser)
Data Type Strings only (objects need to be serialized) Strings only (objects need to be serialized)
Use Case User preferences, non-sensitive persistent data Temporary form data, single-session state

Storage Events

<script> // Listen for changes to localStorage from other tabs/windows window.addEventListener('storage', (event) => { console.log('Storage changed:', { key: event.key, oldValue: event.oldValue, newValue: event.newValue, url: event.url, storageArea: event.storageArea }); }); </script>
Best Practices:
  • Don't store sensitive information in Web Storage (use secure cookies with HttpOnly flag for authentication)
  • Remember to serialize objects with JSON.stringify() and deserialize with JSON.parse()
  • Always handle potential storage errors (e.g., when storage is full or disabled)
  • Be mindful of storage limits, especially for applications that store larger amounts of data
  • Consider using a wrapper library or pattern to handle serialization/deserialization and error handling

3. Geolocation API

The Geolocation API allows websites to access the user's geographical location information, with the user's permission:

<script> // Check if geolocation is supported if ('geolocation' in navigator) { // Get current position navigator.geolocation.getCurrentPosition( // Success callback (position) => { const latitude = position.coords.latitude; const longitude = position.coords.longitude; console.log(`Location: ${latitude}, ${longitude}`); // Additional information available const accuracy = position.coords.accuracy; // in meters const altitude = position.coords.altitude; // may be null const speed = position.coords.speed; // may be null const timestamp = position.timestamp; // time when location was retrieved }, // Error callback (error) => { switch(error.code) { case error.PERMISSION_DENIED: console.error("User denied the request for geolocation"); break; case error.POSITION_UNAVAILABLE: console.error("Location information is unavailable"); break; case error.TIMEOUT: console.error("The request to get location timed out"); break; case error.UNKNOWN_ERROR: console.error("An unknown error occurred"); break; } }, // Options { enableHighAccuracy: true, // use GPS if available timeout: 5000, // timeout after 5 seconds maximumAge: 0 // don't use cached position } ); // Watch position (continuous updates) const watchId = navigator.geolocation.watchPosition( (position) => { console.log(`New location: ${position.coords.latitude}, ${position.coords.longitude}`); }, (error) => { console.error("Error watching position:", error.message); } ); // Stop watching position navigator.geolocation.clearWatch(watchId); } else { console.error("Geolocation is not supported by this browser"); } </script>

Security and Privacy

Use Cases:
  • Location-based search results (e.g., nearby restaurants)
  • Navigation and mapping applications
  • Weather forecasts for the user's current location
  • Delivery tracking and logistics applications
  • Geofencing for location-triggered experiences
  • Location-based games and social applications

4. Drag and Drop API

The HTML5 Drag and Drop API allows you to implement drag-and-drop features in web applications by making elements draggable and defining drop zones:

<!-- HTML --> <div id="draggable" draggable="true">Drag me</div> <div id="dropzone">Drop here</div> <!-- CSS --> <style> #draggable { width: 100px; height: 100px; background-color: #3498db; color: white; text-align: center; line-height: 100px; cursor: move; user-select: none; } #dropzone { width: 200px; height: 200px; border: 2px dashed #ccc; margin-top: 20px; text-align: center; line-height: 200px; } #dropzone.dragover { border-color: #3498db; background-color: rgba(52, 152, 219, 0.1); } </style> <!-- JavaScript --> <script> const draggable = document.getElementById('draggable'); const dropzone = document.getElementById('dropzone'); // Set up draggable element draggable.addEventListener('dragstart', (e) => { // Set data to be transferred e.dataTransfer.setData('text/plain', e.target.id); // Optional: set a drag image // e.dataTransfer.setDragImage(image, xOffset, yOffset); // Set allowed effects e.dataTransfer.effectAllowed = 'move'; }); // Set up drop zone dropzone.addEventListener('dragover', (e) => { // Prevent default to allow drop e.preventDefault(); e.dataTransfer.dropEffect = 'move'; dropzone.classList.add('dragover'); }); dropzone.addEventListener('dragleave', () => { dropzone.classList.remove('dragover'); }); dropzone.addEventListener('drop', (e) => { e.preventDefault(); dropzone.classList.remove('dragover'); // Get the transferred data const id = e.dataTransfer.getData('text/plain'); const draggedElement = document.getElementById(id); // Append the dragged element to the drop zone dropzone.appendChild(draggedElement); }); </script>

Drag and Drop Events

Event Target Description
dragstart Draggable element Fires when the user starts dragging an element
drag Draggable element Fires continuously while the element is being dragged
dragend Draggable element Fires when the drag operation ends (drop or cancel)
dragenter Drop target Fires when a dragged element enters a valid drop target
dragover Drop target Fires continuously while a dragged element is over a drop target
dragleave Drop target Fires when a dragged element leaves a valid drop target
drop Drop target Fires when a dragged element is dropped on a valid target

DataTransfer Object

The dataTransfer object is used to hold data that is being dragged during a drag and drop operation, and to specify the allowed drop effects:

<script> // Set data during dragstart e.dataTransfer.setData('text/plain', 'This text will be transferred'); e.dataTransfer.setData('text/html', '<p>This HTML will be transferred</p>'); e.dataTransfer.setData('application/json', JSON.stringify({ key: 'value' })); // Get data during drop const text = e.dataTransfer.getData('text/plain'); const html = e.dataTransfer.getData('text/html'); const json = JSON.parse(e.dataTransfer.getData('application/json')); // Effects for visual feedback e.dataTransfer.dropEffect = 'copy'; // cursor shows a copy e.dataTransfer.dropEffect = 'move'; // cursor shows a move e.dataTransfer.dropEffect = 'link'; // cursor shows a link // Set allowed effects (during dragstart) e.dataTransfer.effectAllowed = 'copy'; // Allow copy only e.dataTransfer.effectAllowed = 'move'; // Allow move only e.dataTransfer.effectAllowed = 'copyMove'; // Allow both copy and move e.dataTransfer.effectAllowed = 'all'; // Allow all effects </script>
File Drag and Drop: The API also supports dragging files from the user's system into the browser:
<script> dropzone.addEventListener('drop', (e) => { e.preventDefault(); // Access dropped files if (e.dataTransfer.items) { // Using DataTransferItemList interface for (let i = 0; i < e.dataTransfer.items.length; i++) { if (e.dataTransfer.items[i].kind === 'file') { const file = e.dataTransfer.items[i].getAsFile(); console.log('Dropped file:', file.name); // Process file (e.g., with FileReader API) } } } else { // Using DataTransfer interface for (let i = 0; i < e.dataTransfer.files.length; i++) { const file = e.dataTransfer.files[i]; console.log('Dropped file:', file.name); // Process file } } }); </script>

5. Web Workers API

Web Workers allow you to run JavaScript code in background threads, separate from the main execution thread of a web application. This enables computationally intensive tasks without blocking the UI:

<!-- Main thread code (main.js) --> <script> // Create a new worker const worker = new Worker('worker.js'); // Send data to the worker worker.postMessage({ command: 'calculate', data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }); // Receive data from the worker worker.onmessage = function(e) { console.log('Result received from worker:', e.data); }; // Handle errors worker.onerror = function(error) { console.error('Worker error:', error.message); }; // Terminate the worker when no longer needed // worker.terminate(); </script> <!-- Worker code (worker.js in a separate file) --> // Listen for messages from the main thread self.onmessage = function(e) { console.log('Message received in worker:', e.data); if (e.data.command === 'calculate') { // Perform computationally intensive task const result = calculateSum(e.data.data); // Send the result back to the main thread self.postMessage({ status: 'success', result: result }); } }; function calculateSum(numbers) { // Simulate heavy computation let sum = 0; for (let i = 0; i < numbers.length; i++) { sum += numbers[i]; } return sum; }

Types of Web Workers

Type Description
Dedicated Workers Used by a single script instance (most common)
Shared Workers Can be shared between multiple scripts or windows from the same origin
Service Workers Act as proxy servers that sit between web applications, the browser, and the network (used for offline support and push notifications)

Limitations

Workers do not have access to:

Workers do have access to:

Use Cases:
  • Intensive mathematical calculations
  • Large data set processing
  • Image or video processing
  • Background I/O operations
  • Polling for updates from a server
  • Prefetching and caching data for later use

6. Fetch API

The Fetch API provides a modern interface for making HTTP requests, replacing the older XMLHttpRequest. It uses Promises for more manageable asynchronous code:

<!-- Basic GET request --> <script> fetch('https://api.example.com/data') .then(response => { // Check if the response is ok (status 200-299) if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); // Parse the response as JSON }) .then(data => { console.log('Data received:', data); }) .catch(error => { console.error('Fetch error:', error); }); </script> <!-- POST request with options --> <script> fetch('https://api.example.com/submit', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer your-token' }, body: JSON.stringify({ name: 'John Doe', email: 'john@example.com' }) }) .then(response => response.json()) .then(data => console.log('Success:', data)) .catch(error => console.error('Error:', error)); </script> <!-- Using async/await syntax (modern approach) --> <script> async function fetchData() { try { const response = await fetch('https://api.example.com/data'); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const data = await response.json(); console.log('Data received:', data); return data; } catch (error) { console.error('Fetch error:', error); } } fetchData(); </script>

Request Options

Option Description Example
method HTTP method to use 'GET', 'POST', 'PUT', 'DELETE', etc.
headers HTTP headers to include { 'Content-Type': 'application/json' }
body Body content for POST/PUT requests JSON.stringify(data), new FormData(), etc.
mode CORS mode 'cors', 'no-cors', 'same-origin'
credentials Include cookies with request 'omit', 'same-origin', 'include'
cache How to handle cache 'default', 'no-store', 'reload', 'no-cache'
redirect How to handle redirects 'follow', 'error', 'manual'

Response Methods

<script> fetch('https://api.example.com/data') .then(response => { // Response properties console.log('Status:', response.status); console.log('OK:', response.ok); console.log('Status Text:', response.statusText); console.log('Headers:', response.headers); console.log('URL:', response.url); console.log('Type:', response.type); // basic, cors, error, opaque, opaqueredirect // Parse methods (each can only be used once per response) // Choose the appropriate one based on expected content: return response.json(); // Parse as JSON // return response.text(); // Get as plain text // return response.blob(); // Get as Blob (binary data) // return response.formData(); // Parse as FormData // return response.arrayBuffer(); // Get as ArrayBuffer }) .then(data => { console.log('Parsed data:', data); }); </script>
Advanced Usage:
  • Uploading files: Use FormData or Blob with the Fetch API
  • Streaming responses: Process large responses incrementally using response.body and the Streams API
  • Aborting requests: Use AbortController to cancel requests
  • Request/Response cloning: Use request.clone() or response.clone() to create copies that can be used multiple times

7. IndexedDB API

IndexedDB is a low-level API for client-side storage of significant amounts of structured data, including files and blobs. It's more powerful than localStorage, providing indexed database capabilities in the browser:

<script> // Open a database const request = indexedDB.open('MyDatabase', 1); // Create or upgrade the database schema request.onupgradeneeded = function(event) { const db = event.target.result; // Create an object store with a key path const store = db.createObjectStore('customers', { keyPath: 'id' }); // Create indexes for faster searching store.createIndex('name', 'name', { unique: false }); store.createIndex('email', 'email', { unique: true }); }; // Handle success request.onsuccess = function(event) { const db = event.target.result; // Add data function addCustomer(customer) { const transaction = db.transaction(['customers'], 'readwrite'); const store = transaction.objectStore('customers'); const request = store.add(customer); request.onsuccess = function() { console.log('Customer added to the database'); }; request.onerror = function(error) { console.error('Error adding customer:', error); }; } // Get data function getCustomer(id) { const transaction = db.transaction(['customers']); const store = transaction.objectStore('customers'); const request = store.get(id); request.onsuccess = function(event) { if (request.result) { console.log('Customer:', request.result); } else { console.log('Customer not found'); } }; } // Search by index function getCustomerByEmail(email) { const transaction = db.transaction(['customers']); const store = transaction.objectStore('customers'); const index = store.index('email'); const request = index.get(email); request.onsuccess = function() { console.log('Customer by email:', request.result); }; } // Update data function updateCustomer(customer) { const transaction = db.transaction(['customers'], 'readwrite'); const store = transaction.objectStore('customers'); const request = store.put(customer); // put = update or add request.onsuccess = function() { console.log('Customer updated'); }; } // Delete data function deleteCustomer(id) { const transaction = db.transaction(['customers'], 'readwrite'); const store = transaction.objectStore('customers'); const request = store.delete(id); request.onsuccess = function() { console.log('Customer deleted'); }; } // Example usage addCustomer({ id: 1, name: 'John Doe', email: 'john@example.com' }); getCustomer(1); getCustomerByEmail('john@example.com'); updateCustomer({ id: 1, name: 'John Doe', email: 'john.updated@example.com' }); deleteCustomer(1); }; // Handle errors request.onerror = function(event) { console.error('Database error:', event.target.error); }; </script>

Key Concepts

Concept Description
Database Container for object stores, similar to a SQL database
Object Store Similar to a table in a SQL database, holds records (JavaScript objects)
Index Provides a way to quickly locate records by properties other than the key
Transaction A group of operations that succeed or fail together (atomic)
Cursor Mechanism for iterating over multiple records in an object store or index
Key Range Defines a range of keys to select records from an object store or index
Advantages of IndexedDB:
  • Stores virtually unlimited amount of data (unlike localStorage's 5MB limit)
  • Supports complex structured data, including files and blobs
  • Provides indexing for efficient searches
  • Supports transactions for data integrity
  • Is asynchronous, so it doesn't block the main thread
  • Works offline and persists across sessions
Limitations:
  • More complex API with a steeper learning curve
  • Event-based asynchronous nature can be challenging to work with (many developers use wrapper libraries)
  • Can be cleared by the user or the browser when storage space is needed

8. History API

The History API allows manipulation of the browser history and the current URL without a full page refresh, enabling single-page applications (SPAs) to manage browser navigation:

<script> // Navigate forward and backward window.history.back(); // Go back one page window.history.forward(); // Go forward one page window.history.go(-2); // Go back two pages window.history.go(3); // Go forward three pages // Add a new state to the history history.pushState( { page: 2 }, // state object to pass to the new state 'Page 2', // title (ignored by most browsers) '/page2' // URL to display in the address bar ); // Replace the current state history.replaceState( { page: 3 }, // state object 'Page 3', // title '/page3' // URL ); // Handle navigation events window.addEventListener('popstate', function(event) { // event.state contains the state object passed to pushState or replaceState console.log('Navigation state:', event.state); // Update the page content based on the new state if (event.state && event.state.page) { loadPage(event.state.page); } }); // Example of a single-page app navigation function navigateTo(page) { // Update the UI document.getElementById('content').innerHTML = `Content for page ${page}`; // Update the history history.pushState({ page: page }, `Page ${page}`, `/page${page}`); } function loadPage(page) { // Update the UI based on the page from history document.getElementById('content').innerHTML = `Content for page ${page}`; } </script> <!-- Navigation buttons for a SPA --> <nav> <button onclick="navigateTo(1)">Page 1</button> <button onclick="navigateTo(2)">Page 2</button> <button onclick="navigateTo(3)">Page 3</button> </nav> <div id="content"> Content for page 1 </div>

pushState() vs. replaceState()

Method Description Use Case
pushState() Adds a new entry to the history stack Normal navigation in a SPA; allows back button to return to previous states
replaceState() Replaces the current history entry without adding a new one Updating the URL to reflect a parameter change without creating a new history entry
Best Practices:
  • Update the page URL to reflect the current state of the application
  • Make sure back and forward navigation work as expected (handle popstate events)
  • Use meaningful state objects that can help restore the application state
  • Consider using a routing library for complex SPAs
  • Remember that changing the URL with pushState/replaceState doesn't trigger a page load or server request
  • Always update the page content to match the URL for better user experience

9. WebSockets API

The WebSockets API enables two-way communication between a browser and a server, allowing real-time data transfer with lower overhead than HTTP:

<script> // Create a new WebSocket connection const socket = new WebSocket('wss://example.com/socketserver'); // Connection opened socket.addEventListener('open', (event) => { console.log('WebSocket connection established'); // Send a message to the server socket.send('Hello Server!'); // You can send various data formats socket.send(JSON.stringify({ type: 'message', content: 'Hello from client', date: new Date() })); // Send binary data const binaryData = new Uint8Array([1, 2, 3, 4]); socket.send(binaryData.buffer); }); // Listen for messages from the server socket.addEventListener('message', (event) => { console.log('Message from server:', event.data); // Handle different data types if (typeof event.data === 'string') { // Text data try { const jsonData = JSON.parse(event.data); handleJsonData(jsonData); } catch (e) { // Plain text handleTextData(event.data); } } else if (event.data instanceof Blob) { // Binary data (Blob) event.data.arrayBuffer().then(buffer => { handleBinaryData(buffer); }); } else if (event.data instanceof ArrayBuffer) { // Binary data (ArrayBuffer) handleBinaryData(event.data); } }); // Handle errors socket.addEventListener('error', (event) => { console.error('WebSocket error:', event); }); // Connection closed socket.addEventListener('close', (event) => { console.log('WebSocket connection closed with code:', event.code); console.log('Reason:', event.reason); console.log('Clean close:', event.wasClean); // Reconnect if appropriate if (!event.wasClean) { console.log('Attempting to reconnect...'); // Implement reconnection logic } }); // Close the connection when done function closeConnection() { // Normal closure socket.close(1000, 'Work complete'); } </script>

WebSocket vs. HTTP

Feature WebSocket HTTP
Connection Persistent, full-duplex Request-response, stateless
Data Transfer Bidirectional, simultaneous Client requests, server responds
Header Overhead Low after initial handshake Every request includes full headers
Latency Low (single TCP connection) Higher (new connection per request or keep-alive)
Use Case Real-time applications, live data updates Traditional web requests, REST APIs
Use Cases:
  • Live chat applications and messaging platforms
  • Real-time dashboards and monitoring interfaces
  • Collaborative editing tools
  • Live sports updates and stock tickers
  • Multiplayer games
  • Push notifications for web applications
Fallbacks: For browsers that don't support WebSockets, consider implementing fallbacks like:
  • Long polling (client makes repeated requests that server holds until data is available)
  • Server-sent events (SSE) for one-way server-to-client communication
  • WebSocket polyfills or libraries that handle fallbacks automatically

10. Other Notable APIs

File API

Allows web applications to interact with files on the user's device:

<!-- File input --> <input type="file" id="fileInput" multiple> <script> document.getElementById('fileInput').addEventListener('change', (event) => { const files = event.target.files; for (let i = 0; i < files.length; i++) { const file = files[i]; console.log('File:', file.name); console.log('Type:', file.type); console.log('Size:', file.size, 'bytes'); console.log('Last Modified:', new Date(file.lastModified)); // Read file content const reader = new FileReader(); reader.onload = (e) => { const content = e.target.result; console.log('Content:', content); }; reader.onerror = (error) => { console.error('Error reading file:', error); }; // Read as text (for text files) reader.readAsText(file); // Other read methods: // reader.readAsArrayBuffer(file); // reader.readAsBinaryString(file); // reader.readAsDataURL(file); } }); </script>

Web Notifications API

Enables web applications to display system notifications to the user:

<script> // Request permission async function requestNotificationPermission() { const permission = await Notification.requestPermission(); if (permission === 'granted') { console.log('Notification permission granted'); } else { console.log('Notification permission denied'); } } // Show a notification function showNotification() { if (Notification.permission === 'granted') { const notification = new Notification('New Message', { body: 'You received a new message', icon: '/path/to/icon.png', badge: '/path/to/badge.png', vibrate: [200, 100, 200] }); notification.onclick = () => { window.focus(); notification.close(); }; notification.onclose = () => { console.log('Notification was closed'); }; } } // Usage requestNotificationPermission(); showNotification(); </script>

Web Audio API

A high-level API for processing and synthesizing audio in web applications:

<script> // Create an audio context const audioContext = new AudioContext(); // Play a simple tone function playTone(frequency = 440, duration = 1) { const oscillator = audioContext.createOscillator(); const gainNode = audioContext.createGain(); oscillator.type = 'sine'; oscillator.frequency.value = frequency; oscillator.connect(gainNode); gainNode.connect(audioContext.destination); oscillator.start(); // Fade out gainNode.gain.setValueAtTime(1, audioContext.currentTime); gainNode.gain.exponentialRampToValueAtTime( 0.001, audioContext.currentTime + duration ); // Stop after duration oscillator.stop(audioContext.currentTime + duration); } // Load and play an audio file async function playAudio(url) { const response = await fetch(url); const arrayBuffer = await response.arrayBuffer(); const audioBuffer = await audioContext.decodeAudioData(arrayBuffer); const source = audioContext.createBufferSource(); source.buffer = audioBuffer; source.connect(audioContext.destination); source.start(); } </script>

Payment Request API

Streamlines the checkout process by allowing websites to collect payment information with a native interface:

<script> const paymentMethods = [ { supportedMethods: 'basic-card', data: { supportedNetworks: ['visa', 'mastercard'], supportedTypes: ['credit', 'debit'] } } ]; const paymentDetails = { total: { label: 'Total', amount: { currency: 'USD', value: '19.99' } }, displayItems: [ { label: 'Product', amount: { currency: 'USD', value: '15.00' } }, { label: 'Tax', amount: { currency: 'USD', value: '4.99' } } ] }; const options = { requestShipping: true, requestPayerEmail: true, requestPayerName: true }; async function processPayment() { try { const request = new PaymentRequest( paymentMethods, paymentDetails, options ); const response = await request.show(); console.log('Payment response:', response); // Process payment on your server // Complete the payment await response.complete('success'); } catch (error) { console.error('Payment error:', error); } } </script>