How to Invoke a Salesforce Prompt Template from a Lightning Web Component (LWC)?
With the rise of Einstein GenAI, developers are looking for ways to bring the power of Generative AI directly into custom user interfaces. While Salesforce provides robust tools like Prompt Builder, there is currently a technical limitation: you cannot invoke a Prompt Template directly from a Lightning Web Component (LWC).
However, there is a powerful workaround. By using Apex as a bridge, you can trigger these templates and surface AI-generated responses within your custom LWC.
In this guide, we will walk through the architecture and code required to invoke a GenAI Prompt Template from an LWC.
The Architecture: LWC ↔ Apex ↔ Prompt Template
Since LWCs cannot call the ConnectApi for Einstein LLM directly, the flow follows these steps:
- LWC: Captures user input and calls an Apex method.
- Apex: Uses the
ConnectApi.EinsteinLLMclass to provide input to the Prompt Template and generate a response. - LWC: Receives the string response from Apex and renders it for the user.
1. The Apex Controller
The following Apex class, KnowledgeBasePromptController, uses the ConnectApi to invoke a specific template named Knowledge_Base.
/**
* @description Apex controller to invoke the GenAI Prompt Template 'Knowledge_Base' with user-provided input
* and return the rendered output for Experience Cloud users.
* Enforces sharing, FLS, and safe error handling for LWC usage.
*/
public with sharing class KnowledgeBasePromptController {
/**
* @description Invokes the Knowledge_Base GenAI Prompt Template with the provided input (strText)
* and returns the rendered content as a String. Designed for Experience Cloud users.
* Method is non-cacheable due to server-side execution and user input.
* @param strText String user input that will be passed to the prompt template variable 'strText'
* @return String Rendered content from the prompt template
* @throws AuraHandledException if any error occurs during invocation
*/
@AuraEnabled(cacheable=false)
public static String invokeKnowledgeBase(String strText) {
try {
// Validate input existence to prevent unnecessary API calls
if (String.isBlank(strText)) {
return null;
}
// Prepare the input value wrapper required by ConnectApi
ConnectApi.WrappedValue inputValueMap = new ConnectApi.WrappedValue();
inputValueMap.value = strText;
// Map the input variable name (Input:strText) to the wrapped value
Map<String, ConnectApi.WrappedValue> inputParams = new Map<String, ConnectApi.WrappedValue>();
inputParams.put('Input:strText', inputValueMap);
// Configure the generation input settings
ConnectApi.EinsteinPromptTemplateGenerationsInput promptGenerationsInput = new ConnectApi.EinsteinPromptTemplateGenerationsInput();
promptGenerationsInput.inputParams = inputParams;
// Set additional configuration for the LLM interaction
promptGenerationsInput.additionalConfig = new ConnectApi.EinsteinLlmAdditionalConfigInput();
promptGenerationsInput.additionalConfig.numGenerations = 1;
promptGenerationsInput.additionalConfig.enablePiiMasking = true;
promptGenerationsInput.additionalConfig.applicationName = 'PromptTemplateGenerationsInvocable';
promptGenerationsInput.isPreview = false;
// Invoke the Einstein LLM service for the 'Knowledge_Base' template
ConnectApi.EinsteinPromptTemplateGenerationsRepresentation generationsOutput =
ConnectApi.EinsteinLLM.generateMessagesForPromptTemplate('Knowledge_Base', promptGenerationsInput);
// Validate the response to ensure a generation was received
if (generationsOutput == null || generationsOutput.generations == null || generationsOutput.generations.isEmpty()) {
throw new AuraHandledException('No generations returned from the prompt template.');
}
// Extract the text from the first generation result
ConnectApi.EinsteinLLMGenerationItemOutput response = generationsOutput.generations[0];
// Log the response for debugging (consider removing for production)
System.debug(response.text);
return response.text;
} catch (Exception e) {
// Log the actual internal error for backend debugging
System.debug(LoggingLevel.ERROR, 'Error invoking Knowledge Base: ' + e.getMessage());
// Throw a generic user-facing error to avoid leaking system details
// Note: Creating a new exception prevents the raw stack trace from reaching the client
AuraHandledException ahe = new AuraHandledException(e.getMessage());
ahe.setMessage(e.getMessage());
throw ahe;
}
}
}
2. The Lightning Web Component
The LWC provides a simple interface with a lightning-textarea for the user’s question and a lightning-button to trigger the AI generation.
HTML Template
<template>
<section class="slds-card slds-p-around_medium">
<header class="slds-m-bottom_medium">
<h2 class="slds-text-heading_medium">Knowledge Base</h2>
</header>
<div class="slds-grid slds-wrap slds-gutters">
<div class="slds-col slds-size_1-of-1 slds-m-bottom_small">
<lightning-textarea
name="kbInput"
label="Your question"
value={userInput}
onchange={handleInputChange}
placeholder="Type your question...">
</lightning-textarea>
</div>
<div class="slds-col slds-size_1-of-1 slds-m-bottom_small">
<lightning-button
variant="brand"
label="Submit"
onclick={handleSubmit}
disabled={isSubmitDisabled}
class="slds-m-right_small">
</lightning-button>
<template if:true={isLoading}>
<lightning-spinner
size="small"
alternative-text="Loading">
</lightning-spinner>
</template>
</div>
<div class="slds-col slds-size_1-of-1">
<template if:true={errorMessage}>
<div class="slds-text-color_error slds-m-vertical_small" role="alert">
{errorMessage}
</div>
</template>
<template if:true={renderedHtml}>
<lightning-formatted-text
value={renderedHtml}
class="slds-m-vertical_small">
</lightning-formatted-text>
</template>
</div>
</div>
</section>
</template>
JavaScript Controller
/**
* @description LWC controller for invoking the Knowledge_Base GenAI Prompt Template via Apex.
* Accepts user input, calls Apex, and renders the output.
*/
import { LightningElement } from 'lwc';
import invokeKnowledgeBase from '@salesforce/apex/KnowledgeBasePromptController.invokeKnowledgeBase';
export default class KnowledgeBaseInvoker extends LightningElement {
// Component state properties
userInput = '';
isLoading = false;
errorMessage = '';
renderedHtml = '';
/**
* @description Handles input changes for the textarea.
* Updates the state and clears previous results/errors to reset the UI.
* @param {Event} event - The change event from lightning-textarea
*/
handleInputChange(event) {
// capture value safely
this.userInput = event.detail.value || '';
// Clear previous output/error when user changes input to provide immediate feedback
this.errorMessage = '';
this.renderedHtml = '';
}
/**
* @description Submits the input to Apex and renders the output.
* Handles the asynchronous call and error states.
* @returns {Promise<void>}
*/
async handleSubmit() {
// Prevent submission if the button should be disabled
if (this.isSubmitDisabled) {
return;
}
// Set loading state to show spinner
this.isLoading = true;
this.errorMessage = '';
this.renderedHtml = '';
try {
// Invoke the Apex method
const result = await invokeKnowledgeBase({ strText: this.userInput });
// Log result for debugging (Consider removing for production)
console.log('Raw result from Apex:', JSON.stringify(result));
this.renderedHtml = result;
} catch (e) {
// Handle specific Apex errors (LWC specific structure) vs generic JS errors
const msg = (e && e.body && e.body.message)
? e.body.message
: (e && e.message) || 'An unexpected error occurred.';
this.errorMessage = msg;
// Log the full error object for developer debugging
console.error('Error invoking Knowledge Base:', JSON.stringify(e));
} finally {
// Always turn off the spinner regardless of success or failure
this.isLoading = false;
}
}
/**
* @description Computed state for disabling the submit button.
* Ensures we don't submit empty strings or while already loading.
* @returns {boolean} True if submission should be blocked
*/
get isSubmitDisabled() {
return this.isLoading || !this.userInput || this.userInput.trim().length === 0;
}
}
Configuration (js-meta.xml)
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>65.0</apiVersion>
<isExposed>true</isExposed>
<masterLabel>Knowledge Base Invoker</masterLabel>
<description>Invokes the Knowledge_Base GenAI Prompt Template with user input and displays safe HTML. Designed for Experience Cloud.</description>
<targets>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
<target>lightning__RecordPage</target>
<target>lightningCommunity__Page</target>
<target>lightningCommunity__Default</target>
</targets>
</LightningComponentBundle>