Embedding LMA Components in Your Application
Embedding LMA Components in Your Application
Section titled “Embedding LMA Components in Your Application”Overview
Section titled “Overview”LMA provides an embeddable component page that allows you to integrate individual LMA UI components directly into your own application using iframes. This enables you to offer LMA-powered meeting features — live transcription, meeting summaries, AI chat assistants, virtual participant live views, and audio streaming — all within your own product’s UI, without requiring users to navigate to the full LMA application.
The embed page is a chrome-free (no navigation sidebar, top bar, or breadcrumbs) rendering of LMA components, fully controlled via URL query parameters and optionally via the postMessage Web API for cross-origin communication.
Why Embed LMA Components?
Section titled “Why Embed LMA Components?”Use Cases
Section titled “Use Cases”White-Label Meeting Intelligence
- Embed live transcription and AI summaries directly in your customer-facing application
- Offer meeting recording and analysis as a feature of your platform
- Maintain your own branding while leveraging LMA’s backend
Custom Meeting Dashboards
- Build dashboards that combine LMA meeting data with your own application data
- Show only the components relevant to your users (e.g., transcript only, or chat only)
- Control layout and visibility to match your UI design
Virtual Participant Integration
- Embed the VNC live view of a virtual participant in your meeting management UI
- Show real-time meeting transcripts alongside your own meeting controls
- Monitor virtual participant status from within your application
Automated Meeting Workflows
- Pre-populate meeting fields and auto-start recordings from your application
- Control meeting lifecycle (start/stop) programmatically via postMessage
- Receive meeting events (started, stopped, errors) in your parent application
Prerequisites
Section titled “Prerequisites”- LMA deployed and accessible (v0.2.23 or later)
- Your LMA CloudFront endpoint URL (found in CloudFormation Outputs as
CloudFrontEndpoint) - One of the following authentication approaches configured:
- Cognito login (default) — users log in via LMA’s Cognito User Pool
- Cognito Identity Federation — users authenticate via your IdP, federated through Cognito
- Token passing via postMessage — your app obtains tokens and passes them to the iframe
Interactive Demo Page
Section titled “Interactive Demo Page”A ready-to-use demo page is included that showcases the embeddable components inside a mock “Acme CRM” parent application — useful for quickly validating your deployment or for producing screenshots.
▶ Open the live demo (hosted on the LMA docs site — renders directly in the browser)
Source: docs/embeddable-components-demo.html
Enter your LMA CloudFront URL and an existing callId, and click Apply. The page demonstrates:
- A stream-audio widget pre-populated with meeting fields, with parent-app Start/Stop buttons that drive the iframe via
postMessage, plus a live event log showing everyLMA_*event the iframe emits. - A multi-panel dashboard combining
summary,chat, andtranscriptiframes in a CSS Grid layout — all bound to the same meeting.
Virtual Participant Demo Page
Section titled “Virtual Participant Demo Page”A companion demo page showcases the Virtual Participant flow end-to-end: create a VP from the parent app, watch it join a Zoom / Teams / Chime / WebEx meeting via the noVNC live view, and see the transcript and summary panels auto-populate via AppSync subscriptions — all with zero manual refreshes.
Source: docs/embeddable-vp-demo.html
The VP demo is pure HTML (no SDK/auth required in the parent app): it uses a hidden
component=vp-loader iframe to create the VP via postMessage, and then renders a 2×2 grid of
dependent iframes (vnc, vp-details, transcript, summary) that all load as soon as the
backend emits the corresponding events.
Quick Start
Section titled “Quick Start”1. Basic Embed (Stream Audio)
Section titled “1. Basic Embed (Stream Audio)”The simplest way to get started is to embed the Stream Audio component:
<iframe src="https://YOUR_LMA_CLOUDFRONT_URL/#/embed?component=stream-audio" width="100%" height="400px" style="border: none;" allow="microphone; display-capture"></iframe>Important: The
allow="microphone; display-capture"attribute is required for the Stream Audio component to access the user’s microphone and screen audio.
1b. Upload Audio (Pre-recorded)
Section titled “1b. Upload Audio (Pre-recorded)”To let users upload an existing audio/video file instead of streaming live:
<iframe src="https://YOUR_LMA_CLOUDFRONT_URL/#/embed?component=upload-audio" width="100%" height="550px" style="border: none;"></iframe>Upload Audio does not need the
allow="microphone; display-capture"attribute — the file is selected from the user’s device and uploaded directly to Amazon S3.
1c. Combined Stream / Upload Selector
Section titled “1c. Combined Stream / Upload Selector”To show both options with a Tiles-style switcher at the top of the form:
<iframe src="https://YOUR_LMA_CLOUDFRONT_URL/#/embed?component=select-audio" width="100%" height="600px" style="border: none;" allow="microphone; display-capture"></iframe>2. Pre-Populated Stream Audio
Section titled “2. Pre-Populated Stream Audio”Pre-fill the meeting form fields so users just click “Start Streaming”:
<iframe src="https://YOUR_LMA_CLOUDFRONT_URL/#/embed?component=stream-audio&meetingTopic=Sales+Call&participants=Customer&owner=agent@company.com" width="100%" height="400px" style="border: none;" allow="microphone; display-capture"></iframe>3. View a Meeting Transcript
Section titled “3. View a Meeting Transcript”Show the live transcript and AI chat for an existing meeting:
<iframe src="https://YOUR_LMA_CLOUDFRONT_URL/#/embed?component=call-details&callId=My+Meeting+-+2025-01-29T14:30:00" width="100%" height="800px" style="border: none;"></iframe>4. Virtual Participant with VNC Live View
Section titled “4. Virtual Participant with VNC Live View”Show the VNC live view and transcript for a virtual participant session:
<iframe src="https://YOUR_LMA_CLOUDFRONT_URL/#/embed?component=vp-details&vpId=abc-123-def&show=vnc,transcript" width="100%" height="900px" style="border: none;"></iframe>Available Components
Section titled “Available Components”| Component Value | Description | Key Parameters |
|---|---|---|
stream-audio | Stream-only: live meeting form + recording controls (mic / screen audio) | meetingTopic, participants, owner, autoStart |
upload-audio | Upload-only: file-picker form for pre-recorded audio / video + diarization toggle | meetingTopic, participants, owner |
select-audio | Combined page with a top-of-page Stream / Upload mode switcher | meetingTopic, participants, owner |
call-details | Complete call details view (transcript + summary + chat) | callId, show, layout |
transcript | Live meeting transcript only | callId |
summary | Meeting summary only | callId |
chat | Meeting Assist Bot chat only | callId |
vp-details | Virtual participant details with selectable panels | vpId, show, layout |
vnc | VNC live view of virtual participant only | vpId |
meeting-loader | Blank meeting starter page (for programmatic control) | meetingTopic, participants, owner, autoStart |
vp-loader | Programmatic Virtual Participant creator (accepts LMA_CREATE_VP postMessage) | meetingName, meetingPlatform, meetingId, meetingPassword, autoStart |
Query Parameter Reference
Section titled “Query Parameter Reference”Component Selection
Section titled “Component Selection”| Parameter | Type | Default | Description |
|---|---|---|---|
component | string | stream-audio | Which component to render (see table above) |
show | string | (auto) | Comma-separated list of panels to display: transcript, summary, chat, vnc, details |
layout | string | vertical | Layout arrangement: vertical, horizontal, grid |
Meeting Parameters
Section titled “Meeting Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
callId | string | — | Meeting/call ID to load for transcript, summary, or chat views |
vpId | string | — | Virtual participant ID for VP-related views |
meetingTopic | string | — | Pre-fill the meeting topic field |
participants | string | — | Pre-fill the participant label |
owner | string | (user email) | Pre-fill the meeting owner field |
autoStart | boolean | false | Automatically start streaming when the page loads |
Authentication
Section titled “Authentication”| Parameter | Type | Default | Description |
|---|---|---|---|
authMode | string | cognito | Authentication mode: cognito (standard login) or token (postMessage token passing) |
Authentication Options
Section titled “Authentication Options”Option 1: Standard Cognito Login (Default)
Section titled “Option 1: Standard Cognito Login (Default)”The simplest approach. When the iframe loads, if the user is not already authenticated, they’ll see the standard LMA Cognito login form. Once logged in, the session persists across page loads.
<!-- No special auth params needed — uses default Cognito auth --><iframe src="https://YOUR_LMA_CLOUDFRONT_URL/#/embed?component=stream-audio" width="100%" height="400px" style="border: none;" allow="microphone; display-capture"></iframe>Best for: Internal tools, admin dashboards, cases where users already have LMA accounts.
Option 2: Cognito Identity Federation
Section titled “Option 2: Cognito Identity Federation”If your application uses its own Identity Provider (IdP), you can configure Cognito Identity Federation so your users are automatically authenticated in LMA when they’re logged into your app.
Setup Steps:
- In the AWS Console, navigate to your LMA Cognito User Pool
- Add your IdP as a federated identity provider (SAML, OIDC, or Social)
- Configure attribute mapping between your IdP and Cognito
- Update the Cognito App Client to include your IdP
- Users will be redirected to your IdP for login, then back to LMA
Best for: Enterprise SSO, organizations with existing IdP infrastructure.
Option 3: Token Passing via postMessage
Section titled “Option 3: Token Passing via postMessage”For maximum control, your application can obtain Cognito tokens directly (by calling the Cognito API) and pass them to the iframe via the postMessage Web API. This avoids showing any login UI in the iframe.
<iframe id="lma-embed" src="https://YOUR_LMA_CLOUDFRONT_URL/#/embed?component=stream-audio&authMode=token" width="100%" height="400px" style="border: none;" allow="microphone; display-capture"></iframe>
<script>const iframe = document.getElementById('lma-embed');
// Listen for the iframe to signal it's readywindow.addEventListener('message', (event) => { if (event.data.type === 'LMA_AUTH_READY') { // Send authentication tokens to the iframe iframe.contentWindow.postMessage({ type: 'LMA_AUTH', idToken: 'eyJhbGciOiJSUzI1NiIs...', // Cognito ID token accessToken: 'eyJhbGciOiJSUzI1NiIs...', // Cognito access token refreshToken: 'eyJhbGciOiJSUzI1NiIs...' // Cognito refresh token }, 'https://YOUR_LMA_CLOUDFRONT_URL'); }
if (event.data.type === 'LMA_AUTH_SUCCESS') { console.log('LMA iframe authenticated successfully!'); }
if (event.data.type === 'LMA_AUTH_ERROR') { console.error('LMA auth failed:', event.data.error); }});</script>Obtaining Cognito Tokens from Your Backend:
# Python example using boto3import boto3
client = boto3.client('cognito-idp', region_name='us-east-1')
# Authenticate a user and get tokensresponse = client.initiate_auth( ClientId='YOUR_LMA_COGNITO_CLIENT_ID', AuthFlow='USER_PASSWORD_AUTH', # or USER_SRP_AUTH AuthParameters={ 'USERNAME': 'user@example.com', 'PASSWORD': 'user-password' # pragma: allowlist secret })
tokens = { 'idToken': response['AuthenticationResult']['IdToken'], 'accessToken': response['AuthenticationResult']['AccessToken'], 'refreshToken': response['AuthenticationResult']['RefreshToken']}# Pass these tokens to your frontend, which sends them to the iframe via postMessageBest for: Custom applications, white-label solutions, cases where you control the auth flow.
postMessage API Reference
Section titled “postMessage API Reference”The embed page communicates with the parent application via the postMessage Web API. This enables bidirectional control and event notification.
Messages FROM Parent → Iframe
Section titled “Messages FROM Parent → Iframe”Authentication
Section titled “Authentication”// Send auth tokens (when authMode=token)iframe.contentWindow.postMessage({ type: 'LMA_AUTH', idToken: '...', // Required: Cognito ID token JWT accessToken: '...', // Required: Cognito access token JWT refreshToken: '...' // Optional: Cognito refresh token}, targetOrigin);
// Refresh tokensiframe.contentWindow.postMessage({ type: 'LMA_AUTH_REFRESH', idToken: '...', accessToken: '...', refreshToken: '...'}, targetOrigin);Meeting Control
Section titled “Meeting Control”// Start a meeting (for stream-audio and meeting-loader components)iframe.contentWindow.postMessage({ type: 'LMA_START_MEETING', meetingTopic: 'Optional Topic', // Override meeting topic participants: 'Optional Label', // Override participant label owner: 'optional@email.com' // Override owner}, targetOrigin);
// Stop a meetingiframe.contentWindow.postMessage({ type: 'LMA_STOP_MEETING'}, targetOrigin);
// Set meeting parameters (for meeting-loader component)iframe.contentWindow.postMessage({ type: 'LMA_SET_MEETING_PARAMS', meetingTopic: 'New Topic', participants: 'New Participant', owner: 'new@email.com'}, targetOrigin);Virtual Participant Control (vp-loader)
Section titled “Virtual Participant Control (vp-loader)”// Create & join a meeting as a Virtual Participantiframe.contentWindow.postMessage({ type: 'LMA_CREATE_VP', meetingName: 'Globex Q4 Renewal Sync', // Required meetingPlatform: 'ZOOM', // Required: ZOOM | TEAMS | CHIME | WEBEX meetingId: '1234567890', // Required meetingPassword: 'optional' // Optional}, targetOrigin);
// End a running VPiframe.contentWindow.postMessage({ type: 'LMA_END_VP', vpId: 'abc-123-def'}, targetOrigin);
// Pre-fill VP form params without submittingiframe.contentWindow.postMessage({ type: 'LMA_SET_VP_PARAMS', meetingName: '...', meetingPlatform: '...', meetingId: '...', meetingPassword: '...'}, targetOrigin);Messages FROM Iframe → Parent
Section titled “Messages FROM Iframe → Parent”Authentication Events
Section titled “Authentication Events”window.addEventListener('message', (event) => { switch (event.data.type) { case 'LMA_AUTH_READY': // Iframe is ready to receive auth tokens break; case 'LMA_AUTH_SUCCESS': // Authentication was successful break; case 'LMA_AUTH_ERROR': // Authentication failed console.error(event.data.error); break; }});Embed Lifecycle Events
Section titled “Embed Lifecycle Events”window.addEventListener('message', (event) => { switch (event.data.type) { case 'LMA_EMBED_LOADED': // Embed page has loaded // event.data.component - which component loaded // event.data.params - all parsed query params break; case 'LMA_MEETING_LOADER_READY': // Meeting loader is ready for commands // event.data.state - current state (idle, waiting, etc.) break; }});Meeting Events
Section titled “Meeting Events”window.addEventListener('message', (event) => { switch (event.data.type) { case 'LMA_MEETING_STARTED': // Meeting recording has started console.log('Meeting ID:', event.data.callId); break; case 'LMA_MEETING_STOPPED': // Meeting recording has stopped console.log('Meeting ID:', event.data.callId); break; case 'LMA_MEETING_ERROR': // An error occurred console.error(event.data.error); break; case 'LMA_PARAMS_SET': // Meeting parameters were updated successfully break; }});Call Details Events
Section titled “Call Details Events”window.addEventListener('message', (event) => { switch (event.data.type) { case 'LMA_CALL_LOADED': // Call details loaded successfully // event.data.callId - the meeting ID // event.data.status - meeting status (IN_PROGRESS, DONE, etc.) break; }});Virtual Participant Events
Section titled “Virtual Participant Events”window.addEventListener('message', (event) => { switch (event.data.type) { case 'LMA_VP_LOADED': // VP details loaded // event.data.vpId - VP ID // event.data.status - VP status // event.data.callId - associated call ID (if available) break; case 'LMA_VP_STATUS_CHANGED': // VP status changed (real-time update). // Emitted by vp-details/vnc and vp-loader components. // event.data.vpId - VP ID // event.data.status - new status // event.data.callId - associated call ID (becomes available once the // VP joins and the backend creates the call) break; case 'LMA_VP_LOADER_READY': // vp-loader iframe has mounted and is ready to receive LMA_CREATE_VP break; case 'LMA_VP_CREATED': // vp-loader has created the VP record and started the Step Function. // event.data.vpId - VP ID // event.data.status - initial status (usually INITIALIZING) // event.data.meetingName / meetingPlatform / meetingId // event.data.callId - associated call ID if available (usually null here) break; case 'LMA_VP_ERROR': // vp-loader failed to create or end the VP. // event.data.error - human-readable error message break; case 'LMA_VP_PARAMS_SET': // vp-loader accepted an LMA_SET_VP_PARAMS update break; }});Example Integrations
Section titled “Example Integrations”Example 1: Meeting Recording Widget
Section titled “Example 1: Meeting Recording Widget”A compact widget that lets users start a meeting recording with one click:
<!DOCTYPE html><html><head> <title>Meeting Recorder</title> <style> .recorder-widget { width: 600px; height: 350px; border: 1px solid #ddd; border-radius: 8px; overflow: hidden; } </style></head><body> <div class="recorder-widget"> <iframe id="recorder" src="https://YOUR_LMA_URL/#/embed?component=stream-audio&meetingTopic=Quick+Recording&autoStart=false" width="100%" height="100%" style="border: none;" allow="microphone; display-capture" ></iframe> </div>
<script> window.addEventListener('message', (event) => { if (event.data.type === 'LMA_MEETING_STARTED') { document.title = '🔴 Recording...'; console.log('Recording started:', event.data.callId); } if (event.data.type === 'LMA_MEETING_STOPPED') { document.title = 'Meeting Recorder'; console.log('Recording stopped:', event.data.callId); // You could now fetch the transcript via LMA's API } }); </script></body></html>Example 2: Live Transcript Dashboard
Section titled “Example 2: Live Transcript Dashboard”Show a live transcript alongside your own meeting UI:
<div style="display: flex; gap: 16px; height: 100vh;"> <!-- Your meeting UI on the left --> <div style="flex: 1;"> <h2>Your Meeting Interface</h2> <!-- Your custom meeting controls here --> </div>
<!-- LMA transcript on the right --> <div style="flex: 1;"> <iframe src="https://YOUR_LMA_URL/#/embed?component=transcript&callId=YOUR_MEETING_ID" width="100%" height="100%" style="border: none;" ></iframe> </div></div>Example 3: Virtual Participant Monitor
Section titled “Example 3: Virtual Participant Monitor”Monitor a virtual participant with VNC live view and transcript side by side:
<iframe src="https://YOUR_LMA_URL/#/embed?component=vp-details&vpId=YOUR_VP_ID&show=vnc,transcript,chat&layout=horizontal" width="100%" height="800px" style="border: none;"></iframe>Example 4: Programmatic Meeting Control
Section titled “Example 4: Programmatic Meeting Control”Start and stop meetings entirely from your parent application:
<iframe id="meeting" src="https://YOUR_LMA_URL/#/embed?component=meeting-loader&authMode=cognito" width="100%" height="300px" style="border: none;" allow="microphone; display-capture"></iframe>
<button onclick="startMeeting()">Start Meeting</button><button onclick="stopMeeting()">Stop Meeting</button>
<script>const iframe = document.getElementById('meeting');
function startMeeting() { iframe.contentWindow.postMessage({ type: 'LMA_START_MEETING', meetingTopic: 'Automated Meeting', participants: 'Team', owner: 'admin@company.com' }, '*');}
function stopMeeting() { iframe.contentWindow.postMessage({ type: 'LMA_STOP_MEETING' }, '*');}
window.addEventListener('message', (event) => { if (event.data.type === 'LMA_MEETING_STARTED') { console.log('Meeting started! ID:', event.data.callId); // Now you could open a transcript view for this meeting }});</script>Example 5: Multi-Panel Meeting View
Section titled “Example 5: Multi-Panel Meeting View”Show summary, transcript, and chat in a custom grid layout:
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; height: 100vh;"> <!-- Summary in top-left --> <iframe src="https://YOUR_LMA_URL/#/embed?component=summary&callId=YOUR_MEETING_ID" style="border: none; width: 100%; height: 100%;" ></iframe>
<!-- Chat in top-right --> <iframe src="https://YOUR_LMA_URL/#/embed?component=chat&callId=YOUR_MEETING_ID" style="border: none; width: 100%; height: 100%;" ></iframe>
<!-- Transcript spanning full width at bottom --> <iframe src="https://YOUR_LMA_URL/#/embed?component=transcript&callId=YOUR_MEETING_ID" style="border: none; width: 100%; height: 100%; grid-column: 1 / -1;" ></iframe></div>Layout Options
Section titled “Layout Options”When using composite components (call-details, vp-details), you can control how panels are arranged:
Vertical Layout (Default)
Section titled “Vertical Layout (Default)”?layout=verticalPanels stack top-to-bottom. Best for narrow containers or single-column layouts.
Horizontal Layout
Section titled “Horizontal Layout”?layout=horizontalPanels sit side-by-side. Best for wide containers. Falls back to vertical on narrow screens (< 768px).
Grid Layout
Section titled “Grid Layout”?layout=gridPanels arrange in an auto-fit grid (minimum 400px per column). Best for dashboards with multiple panels.
Controlling Panel Visibility
Section titled “Controlling Panel Visibility”Use the show parameter to control which panels appear:
# Show only transcript and chat?show=transcript,chat
# Show VNC and transcript?show=vnc,transcript
# Show everything?show=vnc,transcript,summary,chat,detailsAvailable panels by component:
| Component | Available Panels |
|---|---|
call-details | transcript, summary, chat |
vp-details | vnc, transcript, summary, chat, details |
Note: For single-purpose components (
transcript,summary,chat,vnc), theshowparameter is automatically set. You only needshowwhen usingcall-detailsorvp-detailsand want to customize which panels appear.
Troubleshooting
Section titled “Troubleshooting”Issue: Iframe shows login page instead of component
Section titled “Issue: Iframe shows login page instead of component”Cause: User is not authenticated in the LMA Cognito User Pool.
Solutions:
- Standard auth: The user needs to log in via the Cognito form shown in the iframe
- Token auth: Ensure you’re sending valid tokens via postMessage (see Token Passing)
- Federation: Verify your IdP is configured correctly in Cognito
Issue: Microphone/screen capture not working in iframe
Section titled “Issue: Microphone/screen capture not working in iframe”Cause: Missing iframe permissions.
Solution: Add the allow attribute to your iframe:
<iframe allow="microphone; display-capture; camera" src="..."></iframe>For cross-origin iframes, you may also need:
<iframe allow="microphone https://YOUR_LMA_URL; display-capture https://YOUR_LMA_URL" src="..."></iframe>Issue: postMessage not received by iframe
Section titled “Issue: postMessage not received by iframe”Cause: Origin mismatch or timing issue.
Solutions:
- Wait for the
LMA_AUTH_READYorLMA_EMBED_LOADEDmessage before sending - Verify the target origin matches the iframe’s origin:
iframe.contentWindow.postMessage(data, 'https://YOUR_LMA_CLOUDFRONT_URL');
- Check browser console for cross-origin errors
Issue: “Meeting not found” when using callId
Section titled “Issue: “Meeting not found” when using callId”Cause: The callId doesn’t match any meeting in LMA.
Solutions:
- Verify the callId is correct — copy it from the LMA meetings list
- Meeting IDs in LMA include the topic and timestamp (e.g.,
Sales Call - 2025-01-29T14:30:00.000Z) - URL-encode special characters in the callId:
?callId=Sales%20Call%20-%202025-01-29T14%3A30%3A00.000Z
Issue: Transcript / summary / chat iframe shows nothing when the meeting is started at the same time
Section titled “Issue: Transcript / summary / chat iframe shows nothing when the meeting is started at the same time”Cause: Prior to v0.2.24, if you loaded a component=transcript (or summary /
chat / call-details) iframe with a callId for a meeting that hadn’t been
created yet — for example, the parent app started a stream-audio iframe and a
transcript iframe for the same callId at the same time — the transcript
iframe would show a “Meeting not found” error and you had to refresh the page
once the meeting actually started.
Resolution: This is now handled automatically. The transcript / summary /
chat / call-details / vp-details embed components now subscribe to the
onCreateCall and onUpdateCall AppSync subscriptions. If the meeting does
not yet exist when the iframe loads, the component shows a
“Waiting for meeting to start…” spinner and auto-loads the meeting as soon as
it appears — no page refresh needed.
On successful auto-load, the iframe emits a standard LMA_CALL_LOADED
postMessage event to the parent, just as if it had loaded normally.
Issue: Components appear but data doesn’t load
Section titled “Issue: Components appear but data doesn’t load”Cause: Settings not loaded from SSM Parameter Store.
Solutions:
- Ensure the LMA stack is fully deployed and the settings parameter exists
- Check that the authenticated user has permission to read SSM parameters
- Verify the
REACT_APP_SETTINGS_PARAMETERenvironment variable is set correctly
Issue: VNC viewer shows “Connection lost”
Section titled “Issue: VNC viewer shows “Connection lost””Cause: Virtual participant has ended or VNC endpoint is no longer available.
Solutions:
- Check the VP status — VNC is only available during active sessions
- Verify the VP’s
vncReadyfield istrue - Ensure the VNC WebSocket endpoint is accessible from the user’s browser
Issue: Cross-origin errors in browser console
Section titled “Issue: Cross-origin errors in browser console”Cause: CORS or Content Security Policy restrictions.
Solutions:
- Ensure your LMA CloudFront distribution allows your domain in CORS headers
- If using a Content Security Policy, add the LMA domain to
frame-src:<meta http-equiv="Content-Security-Policy"content="frame-src https://YOUR_LMA_CLOUDFRONT_URL;">
Security Best Practices
Section titled “Security Best Practices”-
Always specify target origin in postMessage calls — avoid using
'*'in production:iframe.contentWindow.postMessage(data, 'https://YOUR_LMA_CLOUDFRONT_URL'); -
Validate message origins in your parent app:
window.addEventListener('message', (event) => {if (event.origin !== 'https://YOUR_LMA_CLOUDFRONT_URL') return;// Process message...}); -
Never expose tokens in URLs — use postMessage for token passing instead of query parameters
-
Use HTTPS for both your application and the LMA iframe
-
Limit iframe permissions — only grant the permissions each component needs:
- Stream Audio:
allow="microphone; display-capture" - Transcript/Summary/Chat: no special permissions needed
- VNC: no special permissions needed
- Stream Audio:
-
Token refresh — if using token auth mode, implement token refresh:
setInterval(() => {iframe.contentWindow.postMessage({type: 'LMA_AUTH_REFRESH',idToken: freshIdToken,accessToken: freshAccessToken,refreshToken: freshRefreshToken}, targetOrigin);}, 45 * 60 * 1000); // Refresh every 45 minutes
URL Builder Quick Reference
Section titled “URL Builder Quick Reference”Base URL: https://YOUR_LMA_CLOUDFRONT_URL/#/embed
Stream Audio (pre-populated):
/#/embed?component=stream-audio&meetingTopic=My+Meeting&participants=Team&owner=me@co.comAuto-start Stream Audio:
/#/embed?component=stream-audio&meetingTopic=Auto+Meeting&autoStart=trueUpload Audio (pre-populated):
/#/embed?component=upload-audio&meetingTopic=Client+Review&participants=Customer&owner=analyst@co.comCombined Stream / Upload selector:
/#/embed?component=select-audioFull Call Details:
/#/embed?component=call-details&callId=MEETING_IDTranscript Only:
/#/embed?component=transcript&callId=MEETING_IDSummary Only:
/#/embed?component=summary&callId=MEETING_IDChat Only:
/#/embed?component=chat&callId=MEETING_IDVP with VNC + Transcript (horizontal):
/#/embed?component=vp-details&vpId=VP_ID&show=vnc,transcript&layout=horizontalVP with All Panels (grid):
/#/embed?component=vp-details&vpId=VP_ID&show=vnc,transcript,summary,chat,details&layout=gridMeeting Loader (waiting for postMessage):
/#/embed?component=meeting-loaderMeeting Loader (with token auth):
/#/embed?component=meeting-loader&authMode=tokenVP Loader (waiting for postMessage):
/#/embed?component=vp-loaderVP Loader (pre-populated, starts on form submit):
/#/embed?component=vp-loader&meetingName=Globex+Q4+Renewal&meetingPlatform=ZOOM&meetingId=1234567890VP Loader (auto-start from URL):
/#/embed?component=vp-loader&meetingName=Globex+Q4+Renewal&meetingPlatform=ZOOM&meetingId=1234567890&autoStart=trueAdditional Resources
Section titled “Additional Resources”- LMA GitHub Repository
- LMA Main README
- LMA Stream Audio Documentation
- LMA Virtual Participant Documentation
- MDN: Window.postMessage()
- MDN: iframe allow attribute
Support
Section titled “Support”For issues or questions:
- Check the Troubleshooting section above
- Review browser console logs for error messages
- Open an issue on the LMA GitHub repository