Skip to content

Survey Integration Recipe

Complete patterns for integrating Sibilance voice surveys into your application.

Overview

This recipe covers common patterns for integrating Sibilance surveys, handling results, and providing a great user experience.

Basic Integration

React Component

tsx
import { useSibilance, FloatingMicButton } from '@sibilance.is/client/react';

function SurveyIntegration() {
  const { voiceState, surveyState, toggleSession } = useSibilance({
    surveyKey: process.env.NEXT_PUBLIC_SIBILANCE_SURVEY_KEY!,
  }, {
    onComplete: async (yaml) => {
      // Submit results to your backend
      await fetch('/api/survey-results', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ results: yaml })
      });
    }
  });

  return (
    <div>
      <FloatingMicButton
        isConnected={voiceState.isConnected}
        onClick={toggleSession}
      />
      
      {surveyState.isActive && (
        <div className="survey-status">
          Survey in progress...
        </div>
      )}
    </div>
  );
}

Vanilla JavaScript

javascript
import { SibilanceClient } from '@sibilance.is/client';

const client = new SibilanceClient({
  surveyKey: 'sibilance_your_key_here',
}, {
  onComplete: async (yaml) => {
    await fetch('/api/survey-results', {
      method: 'POST',
      body: JSON.stringify({ results: yaml })
    });
  }
});

// Start survey
document.getElementById('start-survey').addEventListener('click', async () => {
  await client.connect();
});

Result Handling

Submit to Backend

typescript
const client = new SibilanceClient({
  surveyKey: 'sibilance_your_key_here'
}, {
  onComplete: async (yaml) => {
    try {
      const response = await fetch('/api/survey-results', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ 
          surveyId: 'your-survey-id',
          results: yaml,
          timestamp: new Date().toISOString()
        })
      });
      
      if (!response.ok) {
        throw new Error('Failed to submit results');
      }
      
      const data = await response.json();
      console.log('Results submitted:', data);
    } catch (error) {
      console.error('Error submitting results:', error);
      // Retry logic or show error to user
    }
  }
});

Process Results Locally

typescript
const client = new SibilanceClient({
  surveyKey: 'sibilance_your_key_here'
}, {
  onComplete: (yaml) => {
    // Process results
    const processed = yaml.map(item => ({
      field: item.field,
      value: item.value,
      step: item.sourceStep,
      timestamp: item.timestamp
    }));
    
    // Store locally
    localStorage.setItem('survey-results', JSON.stringify(processed));
    
    // Update UI
    displayResults(processed);
  }
});

Error Handling

Comprehensive Error Handling

typescript
const client = new SibilanceClient({
  surveyKey: 'sibilance_your_key_here'
}, {
  onComplete: async (yaml) => {
    // Handle completion
  },
  onError: (error) => {
    console.error('Survey error:', error);
    
    // Show user-friendly error
    if (error.message.includes('microphone')) {
      showNotification('Please allow microphone access');
    } else if (error.message.includes('survey')) {
      showNotification('Survey not found. Please check your Survey Key.');
    } else {
      showNotification('An error occurred. Please try again.');
    }
  }
});

// Handle connection errors
try {
  await client.connect();
} catch (error) {
  console.error('Failed to connect:', error);
  handleConnectionError(error);
}

Progress Tracking

Show Survey Progress

tsx
function SurveyProgress() {
  const { surveyState } = useSibilance({
    surveyKey: 'sibilance_your_key_here'
  });

  return (
    <div className="survey-progress">
      <h3>Survey Progress</h3>
      
      {surveyState.isActive && (
        <>
          <p>Current step: {surveyState.currentStepId}</p>
          <p>Collected: {surveyState.collectedInfo.length} items</p>
          
          <div className="progress-bar">
            <div 
              className="progress-fill"
              style={{ 
                width: `${(surveyState.collectedInfo.length / 10) * 100}%` 
              }}
            />
          </div>
        </>
      )}
      
      {surveyState.isComplete && (
        <div className="complete">
          ✅ Survey completed!
        </div>
      )}
    </div>
  );
}

Conditional Rendering

Show Survey Only When Needed

tsx
function ConditionalSurvey() {
  const [showSurvey, setShowSurvey] = useState(false);
  const { voiceState, toggleSession } = useSibilance({
    surveyKey: 'sibilance_your_key_here',
    autoStart: false
  });

  if (!showSurvey) {
    return (
      <button onClick={() => setShowSurvey(true)}>
        Start Survey
      </button>
    );
  }

  return (
    <div>
      <button onClick={() => setShowSurvey(false)}>
        Close Survey
      </button>
      
      <FloatingMicButton
        isConnected={voiceState.isConnected}
        onClick={toggleSession}
      />
    </div>
  );
}