Advanced Usage
Advanced patterns for error handling, offline support, and more.
Advanced Usage
Advanced patterns and best practices for production applications.
Error Handling
import { VidtreoRecorder } from '@vidtreo/recorder-react';
import { useState } from 'react';
function RobustRecorder() {
const [error, setError] = useState<string | null>(null);
const handleError = (err: Error) => {
// Handle specific errors
if (err.message.includes('NotAllowedError')) {
setError('Camera access denied. Please allow permissions.');
} else if (err.message.includes('NotFoundError')) {
setError('No camera found. Please connect a camera.');
} else if (err.message.includes('NotSupportedError')) {
setError('Your browser does not support video recording.');
} else if (err.message.includes('Upload failed')) {
setError('Upload failed. Please check your connection.');
} else {
setError(err.message);
}
};
return (
<div>
<VidtreoRecorder
apiKey={import.meta.env.VITE_VIDTREO_API_KEY}
onError={handleError}
onUploadError={handleError}
/>
{error && (
<div className="error-banner">
<p>{error}</p>
<button onClick={() => setError(null)}>Dismiss</button>
</div>
)}
</div>
);
}Retry Logic
function RecorderWithRetry() {
const [retryCount, setRetryCount] = useState(0);
const [lastBlob, setLastBlob] = useState<Blob | null>(null);
const retryUpload = async () => {
if (!lastBlob) return;
try {
// Manual upload using core SDK
const { UploadService } = await import('@vidtreo/recorder');
const service = new UploadService({
apiKey: import.meta.env.VITE_VIDTREO_API_KEY
});
const result = await service.upload(lastBlob);
console.log('Retry successful:', result);
setLastBlob(null);
} catch (err) {
setRetryCount(c => c + 1);
}
};
return (
<VidtreoRecorder
apiKey={import.meta.env.VITE_VIDTREO_API_KEY}
onUploadError={(err) => {
// Store blob for retry
console.error('Upload failed, blob saved for retry');
}}
/>
);
}Offline Support
The SDK automatically queues recordings when offline:
function OfflineAwareRecorder() {
const [isOnline, setIsOnline] = useState(navigator.onLine);
useEffect(() => {
const handleOnline = () => setIsOnline(true);
const handleOffline = () => setIsOnline(false);
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
return (
<div>
{!isOnline && (
<div className="offline-banner">
You are offline. Recordings will upload when connected.
</div>
)}
<VidtreoRecorder
apiKey={import.meta.env.VITE_VIDTREO_API_KEY}
onUploadComplete={(result) => {
console.log('Upload complete:', result.uploadUrl);
}}
/>
</div>
);
}Recording Limits
Enforce recording constraints:
function LimitedRecorder() {
const [recordingCount, setRecordingCount] = useState(0);
const MAX_RECORDINGS = 5;
if (recordingCount >= MAX_RECORDINGS) {
return <p>You have reached the recording limit.</p>;
}
return (
<VidtreoRecorder
apiKey={import.meta.env.VITE_VIDTREO_API_KEY}
maxRecordingTime={60000} // 1 minute max
onUploadComplete={(result) => {
setRecordingCount(c => c + 1);
console.log(`Recording ${recordingCount + 1}/${MAX_RECORDINGS}`);
}}
/>
);
}Analytics Integration
function AnalyticsRecorder() {
const trackEvent = (event: string, data?: object) => {
// Send to your analytics service
analytics.track(event, data);
};
return (
<VidtreoRecorder
apiKey={import.meta.env.VITE_VIDTREO_API_KEY}
onRecordingStart={() => {
trackEvent('recording_started');
}}
onRecordingStop={() => {
trackEvent('recording_stopped');
}}
onUploadProgress={(progress) => {
if (progress === 0.5) {
trackEvent('upload_halfway');
}
}}
onUploadComplete={(result) => {
trackEvent('recording_complete', {
recordingId: result.recordingId,
url: result.uploadUrl
});
}}
onError={(error) => {
trackEvent('recording_error', {
message: error.message
});
}}
/>
);
}Form Integration
Embed recorder in a form:
function FeedbackForm() {
const [videoUrl, setVideoUrl] = useState<string | null>(null);
const [feedback, setFeedback] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
await submitFeedback({
text: feedback,
videoUrl: videoUrl
});
};
return (
<form onSubmit={handleSubmit}>
<textarea
value={feedback}
onChange={(e) => setFeedback(e.target.value)}
placeholder="Describe your feedback..."
/>
<VidtreoRecorder
apiKey={import.meta.env.VITE_VIDTREO_API_KEY}
maxRecordingTime={120000}
userMetadata={{ formType: 'feedback' }}
onUploadComplete={(result) => {
setVideoUrl(result.uploadUrl);
}}
/>
{videoUrl && <p>Video attached</p>}
<button type="submit">Submit Feedback</button>
</form>
);
}Browser Support Detection
function BrowserAwareRecorder() {
const [isSupported, setIsSupported] = useState(true);
useEffect(() => {
// Check for WebCodecs support
const supported =
'VideoEncoder' in window &&
'AudioEncoder' in window &&
navigator.mediaDevices?.getUserMedia;
setIsSupported(!!supported);
}, []);
if (!isSupported) {
return (
<div className="unsupported">
<h3>Browser Not Supported</h3>
<p>Please use Chrome, Edge, or Safari 16.4+</p>
</div>
);
}
return (
<VidtreoRecorder
apiKey={import.meta.env.VITE_VIDTREO_API_KEY}
/>
);
}See Also
- Configuration — All options
- Callbacks — Event handling
- API Reference — Full API