Skip to main content

How to Make External HTTP Callouts from Salesforce LWC

In plain words: When building modern web applications, you often need to talk to third-party services—like checking if a phone number is valid, looking up weather data, or processing payments via an external API. In Salesforce Lightning Web Components (LWC), because your code runs directly in the browser, you can use the standard JavaScript fetch() method to talk directly to external web services without needing to write backend Apex controller code!

Traditionally in Salesforce, if you needed to make an HTTP request to an external server, you had to route the call through an Apex class using the Http and HttpRequest classes. While Apex callouts are still mandatory for secure server-to-server communications, Lightning Web Components run on modern browsers that natively support the standard JavaScript fetch() API.

In this guide, we will walk through how to build a phone number verification component that queries an external REST API directly from your LWC controller.

Step 1: Create the LWC Component

Open your terminal and use the Salesforce CLI to generate your component files:

sf lightning generate component -n verifyPhoneNumber -d force-app/main/default/lwc

Step 2: Build the HTML Markup

Open verifyPhoneNumber.html. We will create a clean UI with an input field for the phone number, a verification button, and a conditional text block to display the results.

<template>
    <lightning-card title="Phone Number Verification" icon-name="standard:phone">
        <div class="slds-p-around_medium">
            
            <lightning-input 
                type="tel" 
                label="Enter Phone Number" 
                value={phoneNumber} 
                onchange={handlePhoneNumberChange}>
            </lightning-input>

            <br/>

            <lightning-button 
                label="Verify Now" 
                variant="brand" 
                onclick={verifyPhoneNumber}>
            </lightning-button>

        </div>
    </lightning-card>

    <!-- Results Section -->
    <template lwc:if={showVerificationResult}>
        <div class="slds-box slds-theme_info slds-m-top_medium">
            <p><strong>Result:</strong> {verificationResult}</p>
        </div>
    </template>
</template>

Step 3: Write the JavaScript Controller (Fetch API)

Open verifyPhoneNumber.js. Here is where we implement the asynchronous fetch() call. We pass the user's input as a JSON payload to an external API endpoint.

import { LightningElement, track } from 'lwc';

export default class VerifyPhoneNumber extends LightningElement {
    @track phoneNumber = '';
    @track showVerificationResult = false;
    @track verificationResult = '';

    handlePhoneNumberChange(event) {
        this.phoneNumber = event.target.value;
    }

    async verifyPhoneNumber() {
        // Replace with your actual external verification service URL
        const endpointUrl = 'https://api.example.com/v1/verify-phone';

        const payload = {
            phoneNumber: this.phoneNumber
        };

        try {
            // Using standard JavaScript fetch API
            const response = await fetch(endpointUrl, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': 'Bearer YOUR_API_KEY' // If your service requires auth
                },
                body: JSON.stringify(payload)
            });

            if (!response.ok) {
                throw new Error(`HTTP error! Status: ${response.status}`);
            }

            const data = await response.json();
            
            // Update UI properties
            this.verificationResult = data.message || 'Phone number is valid!';
            this.showVerificationResult = true;

        } catch (error) {
            console.error('Callout failed:', error);
            this.verificationResult = 'Verification failed. Please check the console.';
            this.showVerificationResult = true;
        }
    }
}
Developer Trap: CORS (Cross-Origin Resource Sharing) Errors
When you make a fetch() request directly from a browser-based LWC to an external server, the external server's domain must allow requests coming from Salesforce. If the server does not return proper CORS headers allowing your Salesforce domain (*.lightning.force.com), the browser will instantly block the request and throw a CORS error. If this happens, you must route your call through an Apex controller using Named Credentials instead!
360 Card: Browser Fetch vs. Apex Callouts
  • Client-Side Fetch (LWC): Great for fast, lightweight widgets, communicating with public APIs, or working around complex client-side interactions. Subject to browser CORS restrictions.
  • Server-Side Apex Callouts: Mandatory if you need to protect private API keys (since client-side code can be inspected in browser dev tools), or if the external API does not support CORS. Requires configuring Remote Site Settings or Named Credentials in Salesforce Setup.
Core Takeaway: Modern Lightning Web Components natively support the standard JavaScript fetch() API, allowing you to perform asynchronous REST calls directly from the browser as long as the target API supports CORS.

Conclusion

Making external HTTP requests directly from a Lightning Web Component gives you immense flexibility when building reactive, highly dynamic user interfaces. By leveraging modern JavaScript async/await syntax and the native fetch() method, you can connect your Salesforce org to external verification engines, shipping trackers, and third-party databases with ease.

Happy coding!