Call Recording

View as MarkdownOpen in Claude

Call recording is essential for many business applications: quality assurance, compliance, training, dispute resolution, and analytics. The SDK provides flexible recording options that let you capture exactly what you need while respecting privacy and compliance requirements.

Recording happens server-side on SignalWire’s infrastructure, so there’s no additional load on your application server. Recordings are stored securely and can be retrieved via webhooks or the SignalWire API.

When to Record

Common recording use cases:

  • Quality assurance: Review agent performance and customer interactions
  • Compliance: Meet regulatory requirements for financial services, healthcare, etc.
  • Training: Build libraries of good (and problematic) call examples
  • Dispute resolution: Have an authoritative record of what was said
  • Analytics: Feed recordings into speech analytics platforms
  • Transcription: Generate text transcripts for search and analysis

Recording Overview

record_call()

  • Starts background recording
  • Continues while conversation proceeds
  • Supports stereo (separate channels) or mono
  • Output formats: WAV, MP3, or MP4
  • Direction: speak only, listen only, or both

stop_record_call()

  • Stops an active recording
  • Uses control_id to target specific recording
  • Recording is automatically stopped on call end

Recording methods across all languages:

LanguageStart RecordingStop Recording
Pythonresult.record_call(control_id="main", stereo=True, format="wav")result.stop_record_call(control_id="main")
TypeScriptresult.recordCall({ controlId: 'main', stereo: true, format: 'wav' })result.stopRecordCall({ controlId: 'main' })

Basic Recording

1from signalwire import AgentBase
2from signalwire.core.function_result import FunctionResult
3
4class RecordingAgent(AgentBase):
5 def __init__(self):
6 super().__init__(name="recording-agent")
7 self.add_language("English", "en-US", "rime.spore")
8
9 self.prompt_add_section(
10 "Role",
11 "You are a customer service agent. "
12 "Start recording when the customer agrees."
13 )
14
15 self.define_tool(
16 name="start_recording",
17 description="Start recording the call with customer consent",
18 parameters={"type": "object", "properties": {}},
19 handler=self.start_recording
20 )
21
22 def start_recording(self, args, raw_data):
23 return (
24 FunctionResult("Recording has started.")
25 .record_call(
26 control_id="main_recording",
27 stereo=True,
28 format="wav"
29 )
30 )
31
32if __name__ == "__main__":
33 agent = RecordingAgent()
34 agent.run()

Recording Parameters

ParameterTypeDefaultDescription
control_idstrNoneIdentifier to stop specific recording
stereoboolFalseTrue for separate L/R channels
formatstr"wav"Output format: “wav”, “mp3”, or “mp4”
directionstr"both"”speak”, “listen”, or “both”
terminatorsstrNoneDTMF digits that stop recording
beepboolFalsePlay beep before recording
input_sensitivityfloat44.0Audio sensitivity threshold
initial_timeoutfloatNoneSeconds to wait for speech (voicemail use)
end_silence_timeoutfloatNoneSilence duration to auto-stop (voicemail use)
max_lengthfloatNoneMaximum recording seconds
status_urlstrNoneWebhook for recording events

Timeout Parameters: For continuous call recording, do not set initial_timeout or end_silence_timeout. These parameters are designed for voicemail-style recordings where you want automatic termination based on speech patterns.

  • Continuous recording: Omit timeout parameters; use stop_record_call() or call termination to end
  • Voicemail recording: Set appropriate values (e.g., initial_timeout=10.0, end_silence_timeout=3.0)

Stereo vs Mono Recording

The stereo parameter determines how audio channels are recorded. This choice significantly affects how you can use the recording afterward.

Stereo Recording (stereo=True)

Records caller and agent on separate channels (left and right):

1def start_stereo_recording(self, args, raw_data):
2 return (
3 FunctionResult("Recording in stereo mode")
4 .record_call(
5 control_id="stereo_rec",
6 stereo=True, # Caller on left, agent on right
7 format="wav"
8 )
9 )

When to use stereo:

  • Speech-to-text transcription: Most transcription services work better with separated audio, correctly attributing speech to each party
  • Speaker diarization: Analysis tools can easily identify who said what
  • Quality review: Isolate agent or caller audio for focused review
  • Training data: Clean separation for building speech models
  • Noise analysis: Identify which side has audio quality issues

Stereo considerations:

  • Larger file sizes (roughly 2x mono)
  • Requires stereo-capable playback for proper review
  • Some basic media players may only play one channel by default

Mono Recording (stereo=False)

Records both parties mixed into a single channel:

1def start_mono_recording(self, args, raw_data):
2 return (
3 FunctionResult("Recording in mono mode")
4 .record_call(
5 control_id="mono_rec",
6 stereo=False, # Mixed audio (default)
7 format="mp3"
8 )
9 )

When to use mono:

  • Simple archival: Just need a record of what was said
  • Storage-constrained environments: Smaller file sizes
  • Human playback: Easier to listen to on any device
  • Basic compliance: Where separate channels aren’t required

Direction Options

1## Record only what the AI/agent speaks
2def record_agent_only(self, args, raw_data):
3 return (
4 FunctionResult("Recording agent audio")
5 .record_call(direction="speak")
6 )
7
8## Record only what the caller says
9def record_caller_only(self, args, raw_data):
10 return (
11 FunctionResult("Recording caller audio")
12 .record_call(direction="listen")
13 )
14
15## Record both sides (default)
16def record_both(self, args, raw_data):
17 return (
18 FunctionResult("Recording full conversation")
19 .record_call(direction="both")
20 )

Recording with Webhook

Receive notifications when recording completes:

1def start_recording_with_callback(self, args, raw_data):
2 return (
3 FunctionResult("Recording started")
4 .record_call(
5 control_id="webhook_rec",
6 status_url="https://example.com/recording-complete"
7 )
8 )

The webhook receives recording metadata including the URL to download the file.

Auto-Stop Recording

Configure automatic stop conditions:

1def start_auto_stop_recording(self, args, raw_data):
2 return (
3 FunctionResult("Recording with auto-stop")
4 .record_call(
5 max_length=300.0, # Stop after 5 minutes
6 end_silence_timeout=5.0, # Stop after 5 seconds of silence
7 terminators="#" # Stop if user presses #
8 )
9 )

Stop Recording

Stop a recording by control_id:

1from signalwire import AgentBase
2from signalwire.core.function_result import FunctionResult
3
4class ControlledRecordingAgent(AgentBase):
5 def __init__(self):
6 super().__init__(name="controlled-recording-agent")
7 self.add_language("English", "en-US", "rime.spore")
8
9 self.prompt_add_section(
10 "Role",
11 "You handle call recordings. You can start and stop recording."
12 )
13
14 self._register_functions()
15
16 def _register_functions(self):
17 self.define_tool(
18 name="start_recording",
19 description="Start recording the call",
20 parameters={"type": "object", "properties": {}},
21 handler=self.start_recording
22 )
23
24 self.define_tool(
25 name="stop_recording",
26 description="Stop recording the call",
27 parameters={"type": "object", "properties": {}},
28 handler=self.stop_recording
29 )
30
31 def start_recording(self, args, raw_data):
32 return (
33 FunctionResult("Recording has started")
34 .record_call(control_id="main")
35 )
36
37 def stop_recording(self, args, raw_data):
38 return (
39 FunctionResult("Recording has stopped")
40 .stop_record_call(control_id="main")
41 )
42
43if __name__ == "__main__":
44 agent = ControlledRecordingAgent()
45 agent.run()

Recording with Beep

Alert the caller that recording is starting:

1def start_recording_with_beep(self, args, raw_data):
2 return (
3 FunctionResult("This call will be recorded")
4 .record_call(
5 beep=True, # Plays a beep before recording starts
6 format="mp3"
7 )
8 )

Complete Example

1#!/usr/bin/env python3
2## compliance_agent.py - Agent with recording compliance features
3from signalwire import AgentBase
4from signalwire.core.function_result import FunctionResult
5
6class ComplianceAgent(AgentBase):
7 """Agent with full recording compliance features"""
8
9 def __init__(self):
10 super().__init__(name="compliance-agent")
11 self.add_language("English", "en-US", "rime.spore")
12
13 self.prompt_add_section(
14 "Role",
15 "You are a customer service agent. Before recording, you must "
16 "inform the customer and get their verbal consent."
17 )
18
19 self.prompt_add_section(
20 "Recording Policy",
21 """
22 1. Always inform customer: "This call may be recorded for quality purposes."
23 2. Ask for consent: "Do you agree to the recording?"
24 3. Only start recording after explicit "yes" or agreement.
25 4. If customer declines, proceed without recording.
26 """
27 )
28
29 self._register_functions()
30
31 def _register_functions(self):
32 self.define_tool(
33 name="start_compliant_recording",
34 description="Start recording after customer consent is obtained",
35 parameters={"type": "object", "properties": {}},
36 handler=self.start_compliant_recording
37 )
38
39 self.define_tool(
40 name="pause_recording",
41 description="Pause recording for sensitive information",
42 parameters={"type": "object", "properties": {}},
43 handler=self.pause_recording
44 )
45
46 self.define_tool(
47 name="resume_recording",
48 description="Resume recording after sensitive section",
49 parameters={"type": "object", "properties": {}},
50 handler=self.resume_recording
51 )
52
53 def start_compliant_recording(self, args, raw_data):
54 call_id = raw_data.get("call_id", "unknown")
55
56 return (
57 FunctionResult("Recording has begun. Thank you for your consent.")
58 .record_call(
59 control_id=f"compliance_{call_id}",
60 stereo=True,
61 format="wav",
62 beep=True,
63 status_url="https://example.com/recordings/status"
64 )
65 .update_global_data({"recording_active": True})
66 )
67
68 def pause_recording(self, args, raw_data):
69 call_id = raw_data.get("call_id", "unknown")
70
71 return (
72 FunctionResult(
73 "Recording paused. You may now provide sensitive information."
74 )
75 .stop_record_call(control_id=f"compliance_{call_id}")
76 .update_global_data({"recording_active": False})
77 )
78
79 def resume_recording(self, args, raw_data):
80 call_id = raw_data.get("call_id", "unknown")
81
82 return (
83 FunctionResult("Recording resumed.")
84 .record_call(
85 control_id=f"compliance_{call_id}",
86 stereo=True,
87 format="wav"
88 )
89 .update_global_data({"recording_active": True})
90 )
91
92if __name__ == "__main__":
93 agent = ComplianceAgent()
94 agent.run()

Format Comparison

The format parameter determines the output file type. Each format has tradeoffs:

FormatBest ForFile SizeQualityNotes
wavTranscription, archivalLargeLosslessUncompressed, no quality loss
mp3General storageSmallLossyGood compression, widely supported
mp4Video callsMediumLossyRequired for video recording

Choosing a format:

  • wav: Use when quality matters more than storage. Best for speech analytics, transcription services, and long-term archival where you might need to reprocess later. Files can be 10x larger than MP3.

  • mp3: Use for general-purpose recording where storage costs matter. Quality is sufficient for human review and most transcription services. Good balance of size and quality.

  • mp4: Required if you’re recording video calls. Contains both audio and video tracks.

Storage and Retention Considerations

Recordings consume storage and may have regulatory requirements. Plan your retention strategy:

Storage costs: A 10-minute mono MP3 recording is roughly 2-3 MB. At scale, this adds up. A business handling 1,000 calls/day generates 60-90 GB/month of recordings.

Retention policies:

  • Financial services: Often required to retain for 5-7 years
  • Healthcare (HIPAA): Typically 6 years
  • General business: 1-2 years is common
  • Training/QA: Keep only what’s valuable

Automated cleanup: Build processes to delete old recordings according to your policy. Don’t assume someone will do it manually.

Access controls: Recordings may contain sensitive information. Restrict access to those who need it for legitimate business purposes.

Recording laws vary by jurisdiction. Understanding your obligations is critical.

One-party consent (e.g., most US states): Only one party needs to know about the recording. The agent itself can be that party, but best practice is still to inform callers.

Two-party/all-party consent (e.g., California, many European countries): All parties must consent before recording. You must:

  1. Inform the caller that recording may occur
  2. Obtain explicit consent before starting
  3. Provide an option to decline
  4. Proceed without recording if declined

Best practice: Regardless of jurisdiction, always inform callers. It builds trust and protects you legally.

Compliance Implementation

1self.prompt_add_section(
2 "Recording Disclosure",
3 """
4 At the start of every call:
5 1. Say: "This call may be recorded for quality and training purposes."
6 2. Ask: "Do you consent to recording?"
7 3. If yes: Call start_recording function
8 4. If no: Say "No problem, I'll proceed without recording" and continue
9 5. NEVER start recording without explicit consent
10 """
11)

Sensitive Information

Some information should never be recorded, or recordings should be paused:

  • Credit card numbers (PCI compliance)
  • Social Security numbers
  • Medical information in non-healthcare contexts
  • Passwords or PINs

Use the pause/resume pattern shown in the complete example to handle these situations.

Recording Best Practices

Compliance

  • Always inform callers before recording
  • Obtain consent where legally required
  • Provide option to decline recording
  • Document consent in call logs
  • Pause recording for sensitive information (credit cards, SSN)
  • Know your jurisdiction’s consent requirements

Technical

  • Use control_id for multiple recordings or pause/resume
  • Use stereo=True for transcription accuracy
  • Use status_url to track recording completion
  • Set max_length to prevent oversized files
  • Handle webhook failures gracefully

Storage

  • Use WAV for quality, MP3 for size, MP4 for video
  • Implement retention policies aligned with regulations
  • Secure storage with encryption at rest
  • Restrict access to recordings
  • Build automated cleanup processes

Quality

  • Test recording quality in your deployment environment
  • Verify both channels are capturing clearly in stereo mode
  • Monitor for failed recordings via status webhooks