Recordings
Submit browser session recordings for AI analysis with frame-level visual descriptions, OCR, and transcription.
/api/feedback/recordingsCreate a recording document (metadata, actions, browser state). Do not embed video in this request. If the response includes presigned fields (uploadUrl, uploadToken, presignedVideoObjectId, presignedVideoObjectKey, presignedVideoContentType), upload bytes with a browser PUT to uploadUrl using Content-Type exactly matching presignedVideoContentType (and any headers your deployment requires for the upload token). If those fields are omitted (local/dev or presign unavailable), upload the file with PUT /api/feedback/recordings/:id/video instead. Optional videoContentType must match the Content-Type of the direct PUT to the presigned URL.
Body Parameters
metadataobjectRequired fields include version, duration, url, title, intent, features, visitedUrlsactionsarrayRecorded user actionsbrowserStateobjectconsoleLogs, networkRequestselementsarrayOptional DOM element snapshotsvideoContentTypestringOptional: video/webm (default), video/mp4, or video/quicktime — must match direct upload PUTResponse
{
"success": true,
"recordingId": "550e8400-e29b-41d4-a716-446655440000",
"videoUploadStatus": "pending",
"status": "pending",
"uploadUrl": "https://…",
"uploadToken": "…",
"presignedVideoObjectId": "obj-…",
"presignedVideoObjectKey": "app/…/recording_<id>.webm",
"presignedVideoContentType": "video/webm",
"presignedTtlSeconds": 300
}/api/feedback/recordings/:id/videoServer-mediated upload: send the recording video as the raw request body (streaming). Requires Content-Type (video/* or application/octet-stream) and Content-Length. Use this when POST create did not return presigned upload fields, or as a fallback if direct-to-storage upload is not available. When presigned fields are present, prefer the direct PUT to uploadUrl described on POST /api/feedback/recordings.
Body Parameters
(body)binaryrequiredRaw WebM/MP4 bytesResponse
{
"success": true,
"recordingId": "550e8400-e29b-41d4-a716-446655440000",
"videoArtifactId": "obj-123",
"videoUrl": "https://..."
}/api/feedback/recordingsList all recordings for the authenticated user.
Response
{
"recordings": [
{
"id": "rec-abc123",
"status": "analyzed",
"createdAt": "2026-03-01T10:00:00Z",
"duration": 120
}
]
}/api/feedback/recordings/:idGet detail for a specific recording.
Response
{
"id": "rec-abc123",
"status": "analyzed",
"sessionId": "session-abc",
"createdAt": "2026-03-01T10:00:00Z",
"duration": 120,
"metadata": {}
}/api/feedback/recordings/:id/videoGet a presigned video download URL for a recording.
Response
{
"videoUrl": "https://storage.example.com/recordings/rec-abc123.webm?token=..."
}/api/feedback/recordings/:id/analyzeTrigger AI analysis of a recording. Uses mech-media for per-frame visual analysis, OCR, and Whisper transcription.
Response
{
"status": "analyzing",
"jobId": "job-xyz"
}/api/feedback/recordings/:id/analysisGet the AI analysis results for a recording.
Response
{
"sections": [
{
"title": "User navigated to pricing page",
"timestamp": 15.2,
"description": "Clicked pricing link in nav...",
"citations": [
{ "type": "console_error", "timestamp": 15.5 }
]
}
]
}/api/feedback/recordings/:id/summaryGet an AI-generated summary of the recording.
Response
{
"summary": "User browsed the pricing page and attempted checkout...",
"keyFindings": ["Found pricing inconsistency", "Checkout form validation error"]
}/api/feedback/recordings/:id/claimClaim an unclaimed recording for the authenticated user.
Response
{
"success": true,
"id": "rec-abc123",
"userId": "user-xyz"
}/api/feedback/recordings/:idDelete a recording and its associated analysis.
Response
204 No Content