Standalone JavaScript Integration
Learn how to use Sibilance with vanilla JavaScript without any framework.
Overview
Sibilance works perfectly with vanilla JavaScript, providing a simple API for voice surveys in any web application.
Installation
Via NPM
bash
npm install @sibilance.is/clientjavascript
import { SibilanceClient } from '@sibilance.is/client';Via CDN
html
<script type="module">
import { SibilanceClient } from 'https://unpkg.com/@sibilance.is/client/dist/index.js';
</script>Quick Start
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Voice Survey Demo</title>
</head>
<body>
<h1>Voice Survey</h1>
<button id="start-survey">Start Survey</button>
<button id="stop-survey" style="display: none;">Stop Survey</button>
<div id="status"></div>
<div id="results"></div>
<script type="module">
import { SibilanceClient } from '@sibilance.is/client';
// Create Sibilance client
const client = new SibilanceClient({
surveyKey: 'sibilance_your_key_here',
}, {
onComplete: (yaml) => {
console.log('Survey completed!', yaml);
document.getElementById('results').innerHTML =
'<pre>' + JSON.stringify(yaml, null, 2) + '</pre>';
}
});
// UI elements
const startBtn = document.getElementById('start-survey');
const stopBtn = document.getElementById('stop-survey');
const status = document.getElementById('status');
// Event handlers
startBtn.addEventListener('click', async () => {
try {
await client.connect();
startBtn.style.display = 'none';
stopBtn.style.display = 'inline-block';
status.textContent = 'Survey started! Speak to interact.';
} catch (error) {
status.textContent = 'Failed to start: ' + error.message;
}
});
stopBtn.addEventListener('click', async () => {
await client.disconnect();
startBtn.style.display = 'inline-block';
stopBtn.style.display = 'none';
status.textContent = 'Survey stopped.';
});
// Subscribe to state changes
client.onStateChange((state) => {
if (state.isConnected) {
status.textContent = 'Connected';
if (state.isUserSpeaking) {
status.textContent += ' - Listening...';
} else if (state.isAIThinking) {
status.textContent += ' - Thinking...';
} else if (state.isAISpeaking) {
status.textContent += ' - Speaking...';
}
} else {
status.textContent = 'Disconnected';
}
});
</script>
</body>
</html>Complete Example
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Voice Survey</title>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.survey-controls {
position: fixed;
bottom: 20px;
right: 20px;
display: flex;
gap: 10px;
}
.survey-button {
padding: 15px 30px;
font-size: 16px;
border: none;
border-radius: 8px;
cursor: pointer;
background: #007bff;
color: white;
}
.survey-button:hover {
background: #0056b3;
}
.survey-button.stop {
background: #dc3545;
}
.survey-status {
position: fixed;
top: 20px;
right: 20px;
padding: 10px 20px;
background: #f8f9fa;
border-radius: 8px;
border: 1px solid #dee2e6;
}
.survey-status.connected {
background: #d4edda;
border-color: #c3e6cb;
}
.survey-progress {
margin-top: 40px;
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
}
.collected-info {
margin-top: 20px;
}
.info-item {
padding: 10px;
margin: 5px 0;
background: white;
border-radius: 4px;
border-left: 3px solid #007bff;
}
</style>
</head>
<body>
<h1>Voice Survey Demo</h1>
<div class="survey-status" id="status">
Disconnected
</div>
<div class="survey-controls">
<button class="survey-button" id="start-survey">🎤 Start Survey</button>
<button class="survey-button stop" id="stop-survey" style="display: none;">⏹️ Stop Survey</button>
</div>
<div class="survey-progress" id="progress" style="display: none;">
<h3>Survey Progress</h3>
<p id="current-step">Current step: -</p>
<p id="collected-count">Collected: 0 items</p>
</div>
<div class="collected-info" id="collected-info">
<h3>Collected Information</h3>
<div id="info-list"></div>
</div>
<script type="module">
import { SibilanceClient } from '@sibilance.is/client';
// Create client
const client = new SibilanceClient({
surveyKey: 'sibilance_your_key_here',
}, {
onComplete: async (yaml) => {
console.log('Survey completed!', yaml);
// Show results
document.getElementById('collected-info').innerHTML = `
<h3>Survey Completed!</h3>
<pre>${JSON.stringify(yaml, null, 2)}</pre>
`;
// Submit to backend
try {
const response = await fetch('/api/survey-results', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ results: yaml })
});
if (response.ok) {
console.log('Results submitted successfully!');
}
} catch (error) {
console.error('Failed to submit results:', error);
}
},
onRecordInformation: (info) => {
console.log('Recorded:', info.field, '=', info.value);
updateCollectedInfo();
},
onError: (error) => {
console.error('Survey error:', error);
document.getElementById('status').textContent = 'Error: ' + error.message;
},
onStepChange: (stepId) => {
console.log('Step changed to:', stepId);
document.getElementById('current-step').textContent = `Current step: ${stepId}`;
}
});
// UI elements
const startBtn = document.getElementById('start-survey');
const stopBtn = document.getElementById('stop-survey');
const status = document.getElementById('status');
const progress = document.getElementById('progress');
// Update collected info display
function updateCollectedInfo() {
const surveyState = client.getSurveyState();
const infoList = document.getElementById('info-list');
if (surveyState.collectedInfo.length === 0) {
infoList.innerHTML = '<p>No information collected yet.</p>';
return;
}
infoList.innerHTML = surveyState.collectedInfo.map(info => `
<div class="info-item">
<strong>${info.field}:</strong> ${info.value}
${info.sourceStep ? `<small> (from ${info.sourceStep})</small>` : ''}
</div>
`).join('');
document.getElementById('collected-count').textContent =
`Collected: ${surveyState.collectedInfo.length} items`;
}
// Event handlers
startBtn.addEventListener('click', async () => {
try {
await client.connect();
startBtn.style.display = 'none';
stopBtn.style.display = 'inline-block';
progress.style.display = 'block';
status.textContent = 'Connected';
status.classList.add('connected');
} catch (error) {
console.error('Failed to start session:', error);
status.textContent = 'Failed to start: ' + error.message;
}
});
stopBtn.addEventListener('click', async () => {
await client.disconnect();
startBtn.style.display = 'inline-block';
stopBtn.style.display = 'none';
status.textContent = 'Disconnected';
status.classList.remove('connected');
});
// Subscribe to state changes
client.onStateChange((state) => {
if (state.isConnected) {
status.textContent = 'Connected';
status.classList.add('connected');
if (state.isUserSpeaking) {
status.textContent = '🎤 Listening...';
} else if (state.isAIThinking) {
status.textContent = '🤔 Thinking...';
} else if (state.isAISpeaking) {
status.textContent = '🔊 Speaking...';
}
// Update progress
const surveyState = client.getSurveyState();
if (surveyState.isActive) {
document.getElementById('current-step').textContent =
`Current step: ${surveyState.currentStepId || 'Unknown'}`;
updateCollectedInfo();
}
} else {
status.textContent = 'Disconnected';
status.classList.remove('connected');
}
});
// Initial update
updateCollectedInfo();
</script>
</body>
</html>Survey State Management
Access Survey State
javascript
// Get current survey state
const surveyState = client.getSurveyState();
console.log('Is active:', surveyState.isActive);
console.log('Current step:', surveyState.currentStepId);
console.log('Collected info:', surveyState.collectedInfo);
console.log('Conversation log:', surveyState.conversationLog);
console.log('Is complete:', surveyState.isComplete);Track Collected Information
javascript
const client = new SibilanceClient({
surveyKey: 'sibilance_your_key_here'
}, {
onRecordInformation: (info) => {
console.log(`Recorded ${info.field}: ${info.value}`);
// Update UI
const infoList = document.getElementById('collected-info');
const item = document.createElement('div');
item.textContent = `${info.field}: ${info.value}`;
infoList.appendChild(item);
}
});Display Conversation Log
javascript
function displayConversation() {
const surveyState = client.getSurveyState();
const logContainer = document.getElementById('conversation-log');
logContainer.innerHTML = surveyState.conversationLog.map(entry => `
<div class="log-entry ${entry.speaker}">
<strong>${entry.speaker === 'ai' ? 'AI' : 'User'}:</strong>
<p>${entry.message}</p>
<small>${new Date(entry.timestamp).toLocaleTimeString()}</small>
</div>
`).join('');
}
// Update on new entries
const client = new SibilanceClient({
surveyKey: 'sibilance_your_key_here'
}, {
onLogConversation: (speaker, message) => {
displayConversation();
}
});Error Handling
javascript
try {
await client.connect();
} catch (error) {
console.error('Failed to start session:', error);
// Show user-friendly error
if (error.message.includes('microphone')) {
alert('Please allow microphone access to use voice surveys.');
} else if (error.message.includes('survey')) {
alert('Survey not found. Please check your Survey Key.');
} else {
alert('Failed to start survey. Please try again.');
}
}
// Or use onError callback
const client = new SibilanceClient({
surveyKey: 'sibilance_your_key_here'
}, {
onError: (error) => {
console.error('Survey error:', error);
showErrorNotification(error.message);
}
});Best Practices
- Cleanup - Always stop session and unsubscribe on page unload
- Error Handling - Handle errors gracefully with user-friendly messages
- State Management - Subscribe to state changes for UI updates
- Results Submission - Submit survey results to your backend
- Permissions - Request microphone permissions early
- Progressive Enhancement - Ensure app works without voice
Browser Support
Sibilance requires:
- Modern browser with Web Audio API
- Microphone access
- HTTPS (required for microphone)
Check for support:
javascript
if ('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices) {
// Sibilance is supported
} else {
console.warn('Voice features not supported in this browser');
}Related
- Web Component - Web component integration
- React - React integration
- Sibilance Client - Core client API
- API Reference - Complete API documentation