Next.js Integration
Learn how to integrate Sibilance voice surveys with Next.js applications.
Overview
Sibilance works seamlessly with Next.js, supporting both App Router and Pages Router patterns.
Installation
bash
npm install @sibilance.is/clientApp Router (Next.js 13+)
Quick Start
tsx
// app/components/VoiceSurvey.tsx
'use client';
import { useSibilance, FloatingMicButton } from '@sibilance.is/client/react';
export function VoiceSurvey() {
const { voiceState, surveyState, toggleSession } = useSibilance({
surveyKey: process.env.NEXT_PUBLIC_SIBILANCE_SURVEY_KEY!,
}, {
onComplete: async (yaml) => {
console.log('Survey completed!', yaml);
// Submit to your API route
await fetch('/api/survey-results', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ results: yaml })
});
}
});
return (
<FloatingMicButton
isConnected={voiceState.isConnected}
onClick={toggleSession}
position="bottom-right"
/>
);
}tsx
// app/layout.tsx
import { VoiceSurvey } from './components/VoiceSurvey';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<VoiceSurvey />
</body>
</html>
);
}Pages Router (Next.js 12 and below)
Quick Start
tsx
// pages/_app.tsx
import { useSibilance, FloatingMicButton } from '@sibilance.is/client/react';
import type { AppProps } from 'next/app';
function MyApp({ Component, pageProps }: AppProps) {
const { voiceState, surveyState, toggleSession } = useSibilance({
surveyKey: process.env.NEXT_PUBLIC_SIBILANCE_SURVEY_KEY!,
}, {
onComplete: async (yaml) => {
// Submit to API route
await fetch('/api/survey-results', {
method: 'POST',
body: JSON.stringify({ results: yaml })
});
}
});
return (
<>
<Component {...pageProps} />
<FloatingMicButton
isConnected={voiceState.isConnected}
onClick={toggleSession}
position="bottom-right"
/>
</>
);
}
export default MyApp;Complete Example
tsx
// app/components/VoiceSurvey.tsx
'use client';
import { useSibilance, FloatingMicButton } from '@sibilance.is/client/react';
import { useEffect, useState } from 'react';
export function VoiceSurvey() {
const [results, setResults] = useState<any[]>([]);
const { voiceState, surveyState, toggleSession } = useSibilance({
surveyKey: process.env.NEXT_PUBLIC_SIBILANCE_SURVEY_KEY!,
}, {
onComplete: async (yaml) => {
console.log('Survey completed!', yaml);
setResults(yaml);
// Submit to API route
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!');
}
},
onRecordInformation: (info) => {
console.log('Recorded:', info.field, '=', info.value);
},
onError: (error) => {
console.error('Survey error:', error);
}
});
return (
<>
{/* Survey status */}
{surveyState.isActive && (
<div className="survey-status">
<p>Survey in progress...</p>
<p>Current step: {surveyState.currentStepId}</p>
</div>
)}
{/* Floating microphone button */}
<FloatingMicButton
isConnected={voiceState.isConnected}
onClick={toggleSession}
position="bottom-right"
/>
</>
);
}tsx
// app/layout.tsx
import { VoiceSurvey } from './components/VoiceSurvey';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<VoiceSurvey />
</body>
</html>
);
}API Routes Integration
Create an API route to handle survey results:
typescript
// app/api/survey-results/route.ts
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
try {
const { results } = await request.json();
// Validate results
if (!Array.isArray(results)) {
return NextResponse.json(
{ error: 'Invalid results format' },
{ status: 400 }
);
}
// Process results (save to database, send email, etc.)
await processSurveyResults(results);
return NextResponse.json({ success: true });
} catch (error) {
console.error('Failed to process survey results:', error);
return NextResponse.json(
{ error: 'Failed to process results' },
{ status: 500 }
);
}
}
async function processSurveyResults(results: any[]) {
// Your processing logic
// e.g., save to database, send webhook, etc.
}Server Components
Sibilance works with Next.js server components by using client components for voice functionality:
tsx
// app/page.tsx (Server Component)
import { ProductList } from './components/ProductList';
import { VoiceSurvey } from './components/VoiceSurvey';
export default async function Home() {
const products = await fetchProducts();
return (
<main>
<h1>Products</h1>
<ProductList products={products} />
<VoiceSurvey />
</main>
);
}tsx
// app/components/VoiceSurvey.tsx (Client Component)
'use client';
import { useSibilance, FloatingMicButton } from '@sibilance.is/client/react';
export function VoiceSurvey() {
const { voiceState, toggleSession } = useSibilance({
surveyKey: process.env.NEXT_PUBLIC_SIBILANCE_SURVEY_KEY!,
});
return (
<FloatingMicButton
isConnected={voiceState.isConnected}
onClick={toggleSession}
/>
);
}Environment Variables
Store your Survey Key securely:
bash
# .env.local
NEXT_PUBLIC_SIBILANCE_SURVEY_KEY=sibilance_your_key_heretsx
const { voiceState, toggleSession } = useSibilance({
surveyKey: process.env.NEXT_PUBLIC_SIBILANCE_SURVEY_KEY!,
});Best Practices
- Use Client Components - Sibilance requires client-side JavaScript
- Environment Variables - Store Survey Key in environment variables
- Server Components - Keep voice logic in client components
- Error Boundaries - Wrap Sibilance components in error boundaries
- Loading States - Handle loading states during survey initialization
- API Routes - Use API routes for submitting survey results
Troubleshooting
"useRouter must be used in a Client Component"
Make sure your Sibilance setup is in a client component:
tsx
'use client'; // Add this at the top
import { useSibilance } from '@sibilance.is/client/react';Hydration Errors
Avoid using Sibilance state during SSR:
tsx
function MyComponent() {
const { surveyState } = useSibilance({
surveyKey: process.env.NEXT_PUBLIC_SIBILANCE_SURVEY_KEY!
});
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) return null;
return <div>{surveyState.isActive && 'Survey active'}</div>;
}Survey Not Loading
- Verify Survey Key is correct
- Check environment variable is set
- Verify survey is active in Sibilance platform
- Check domain restrictions allow your domain
- Check browser console for errors
Related
- React Integration - React-specific patterns
- Sibilance Client - Core client API
- API Reference - Complete API documentation