5-Minute Quick Start β Speak AI Recorder Embed
Step 1: Basic Iframe Embedding
<!-- Minimal Embedding -->
<iframe
src="https://recorder.speakai.co/iframe/YOUR_TOKEN_HERE"
allow="microphone; camera"
width="100%"
height="700px">
</iframe>
Step 2: Add Query Parameters
<!-- With Query Parameters -->
<iframe
src="https://recorder.speakai.co/iframe/YOUR_TOKEN_HERE?hideWaveform=true&hideTitle=true&submitLabel=Send"
allow="microphone; camera"
width="100%"
height="700px">
</iframe>
Step 3: Add PostMessage Control
// Get iframe reference
const iframe = document.querySelector('iframe');
// Start recording
iframe.contentWindow.postMessage({ action: 'start' }, 'https://recorder.speakai.co');
// Stop recording
iframe.contentWindow.postMessage({ action: 'stop' }, 'https://recorder.speakai.co');
// Listen for responses
window.addEventListener('message', (event) => {
if (event.origin !== 'https://recorder.speakai.co') return;
const response = JSON.parse(event.data);
console.log('Response:', response);
});
βοΈ Query Parameters Reference
Parameter | Type | Default | Description |
hideWaveform | boolean | false | Hide audio waveform visualization |
hideTitle | boolean | false | Hide title/header text |
submitLabel | string | "Upload" | Custom submit button text |
hideSubmit | boolean | false | Hide submit button |
preselect | string | "audio" | "video" | "upload" | "screenshare" | Pre-select recording type |
name | string | "" | Pre-fill name field |
string | "" | Pre-fill email field | |
folderId | string | "" | Pre-fill folder ID |
field1 - field10 | string | "" | Pre-fill custom question answers (up to 10) |
Examples
Hide waveform:
?hideWaveform=true
Hide title:
?hideTitle=true
Custom button:
?submitLabel=Send%20Recording
All combined:
?hideWaveform=true&hideTitle=true&submitLabel=Complete
Pre-select recording type:
?preselect=video
Pre-fill name:
?name=John%20Doe
Pre-fill email:
[email protected]
Pre-fill folder ID:
?folderId=123456
Pre-fill custom question answers:
?field1=Answer%201&field2=Answer%202&field3=Answer%203
π PostMessage API Reference
Commands (Parent β Iframe)
// Start recording
{
action: 'start',
timestamp: Date.now() // optional
}
// Stop recording
{
action: 'stop',
timestamp: Date.now() // optional
}
Responses (Iframe β Parent)
// Success
{
source: 'speak-embed-recorder',
status: 'success',
message: 'Recording started',
timestamp: '2025-10-09T10:30:00.000Z',
data: { action: 'start' }
}
// Error
{
source: 'speak-embed-recorder',
status: 'error',
message: 'Recording already in progress',
timestamp: '2025-10-09T10:30:00.000Z'
}
π‘ Common Patterns
Pattern 1: Minimal UI
<iframe
src="https://recorder.speakai.co/iframe/TOKEN?hideWaveform=true&hideTitle=true"
allow="microphone; camera"
style="width: 100%; height: 500px; border: none;">
</iframe>
Pattern 2: Custom Branding
<iframe
src="https://recorder.speakai.co/iframe/TOKEN?submitLabel=Submit%20to%20Support"
allow="microphone; camera">
</iframe>
Pattern 3: External Controls
<div class="recording-controls">
<button onclick="startRecording()">π΄ Start</button>
<button onclick="stopRecording()">βΉ Stop</button>
<div id="status">Ready</div>
</div>
<iframe id="recorder" src="https://recorder.speakai.co/iframe/TOKEN"></iframe>
<script>
const iframe = document.getElementById('recorder');
const status = document.getElementById('status');
function startRecording() {
iframe.contentWindow.postMessage({action: 'start'}, '*');
status.textContent = 'Recording...';
}
function stopRecording() {
iframe.contentWindow.postMessage({action: 'stop'}, '*');
status.textContent = 'Stopped';
}
window.addEventListener('message', (e) => {
const response = JSON.parse(e.data);
if (response.status === 'error') {
status.textContent = 'Error: ' + response.message;
}
});
</script>
βοΈ Troubleshooting
Iframe Not Loading
const iframe = document.querySelector('iframe');
console.log('Iframe loaded:', iframe.contentWindow !== null);
iframe.addEventListener('load', () => {
console.log('Iframe loaded successfully');
});
PostMessage Not Working
const iframe = document.querySelector('iframe');
console.log('Iframe found:', iframe !== null);
console.log('ContentWindow:', iframe.contentWindow);
function sendDebugMessage(action) {
console.log('Sending:', action);
iframe.contentWindow.postMessage({ action: action }, '*');
console.log('Message sent');
}
sendDebugMessage('start');
Parameters Not Applied
const iframe = document.querySelector('iframe');
console.log('Iframe src:', iframe.src);
const url = new URL(iframe.src);
console.log('hideWaveform:', url.searchParams.get('hideWaveform'));
console.log('hideTitle:', url.searchParams.get('hideTitle'));
console.log('submitLabel:', url.searchParams.get('submitLabel'));
βοΈ Framework Examples
React
import { useEffect, useRef } from 'react';
function RecorderEmbed({ token }) {
const iframeRef = useRef(null);
useEffect(() => {
const handleMessage = (event) => {
if (event.origin !== 'https://recorder.speakai.co') return;
const response = JSON.parse(event.data);
console.log('Recorder:', response);
};
window.addEventListener('message', handleMessage);
return () => window.removeEventListener('message', handleMessage);
}, []);
const startRecording = () => {
iframeRef.current?.contentWindow.postMessage({ action: 'start' }, 'https://recorder.speakai.co');
};
const stopRecording = () => {
iframeRef.current?.contentWindow.postMessage({ action: 'stop' }, 'https://recorder.speakai.co');
};
return (
<div>
<div>
<button onClick={startRecording}>Start</button>
<button onClick={stopRecording}>Stop</button>
</div>
<iframe
ref={iframeRef}
src={`https://recorder.speakai.co/iframe/${token}?hideWaveform=true`}
allow="microphone; camera"
style={{ width: '100%', height: '700px', border: 'none' }}
/>
</div>
);
}
Vue
<template>
<div>
<div>
<button @click="startRecording">Start</button>
<button @click="stopRecording">Stop</button>
</div>
<iframe
ref="recorder"
:src="iframeUrl"
allow="microphone; camera"
style="width: 100%; height: 700px; border: none"
/>
</div>
</template>
<script>
export default {
props: ['token'],
computed: {
iframeUrl() {
return `https://recorder.speakai.co/iframe/${this.token}?hideWaveform=true`;
}
},
mounted() {
window.addEventListener('message', this.handleMessage);
},
beforeUnmount() {
window.removeEventListener('message', this.handleMessage);
},
methods: {
handleMessage(event) {
if (event.origin !== 'https://recorder.speakai.co') return;
const response = JSON.parse(event.data);
console.log('Recorder:', response);
},
startRecording() {
this.$refs.recorder.contentWindow.postMessage(
{ action: 'start' },
'https://recorder.speakai.co'
);
},
stopRecording() {
this.$refs.recorder.contentWindow.postMessage(
{ action: 'stop' },
'https://recorder.speakai.co'
);
}
}
}
</script>
Angular
import { Component, ElementRef, ViewChild, OnInit, OnDestroy } from '@angular/core';
@Component({
selector: 'app-recorder',
template: `
<div>
<button (click)="startRecording()">Start</button>
<button (click)="stopRecording()">Stop</button>
</div>
<iframe
#recorder
[src]="iframeUrl"
allow="microphone; camera"
style="width: 100%; height: 700px; border: none">
</iframe>
`
})
export class RecorderComponent implements OnInit, OnDestroy {
@ViewChild('recorder') iframeElement: ElementRef;
iframeUrl = 'https://recorder.speakai.co/iframe/TOKEN?hideWaveform=true';
ngOnInit() {
window.addEventListener('message', this.handleMessage);
}
ngOnDestroy() {
window.removeEventListener('message', this.handleMessage);
}
handleMessage = (event: MessageEvent) => {
if (event.origin !== 'https://recorder.speakai.co') return;
const response = JSON.parse(event.data);
console.log('Recorder:', response);
};
startRecording() {
const iframe = this.iframeElement.nativeElement as HTMLIFrameElement;
iframe.contentWindow.postMessage({ action: 'start' }, 'https://recorder.speakai.co');
}
stopRecording() {
const iframe = this.iframeElement.nativeElement as HTMLIFrameElement;
iframe.contentWindow.postMessage({ action: 'stop' }, 'https://recorder.speakai.co');
}
}
Support
For issues or questions:
Check the troubleshooting section above
Review the full test plan document
Use the test embedder page to debug
Check the browser console for error messages
Contact us at [email protected]