Behavioral Signals API Python SDK
Official Python SDK for the Behavioral Signals API.
Analyze human behavior and detect deepfake speech using batch and real-time audio APIs. Experimental video deepfake detection is also available in batch mode.
Python SDK Documentation · Examples · PyPI · Contributing
Features
- Behavioral Analysis — analyze human behavior from speech in batch and real-time streaming modes
- Deepfake Detection — detect synthetic or manipulated speech in batch and real-time streaming modes
- Video Deepfake Detection (Experimental, Batch Only) — analyze both the video frames and audio track of supported video files
- Core Speech Attributes (Batch Only) — automatic speech recognition (ASR), speaker diarization, and language identification
- Embeddings — retrieve speaker and behavioral embeddings from the Behavioral API, or speaker and deepfake embeddings from the Deepfakes API
- S3 Input — submit audio and video using S3 presigned URLs
- MCP Server — use Behavioral Signals from MCP-compatible AI assistants
Quickstart
Install
pip install behavioralsignals
Requires Python 3.10 or later.
Configure credentials
Create an account and API key in the Behavioral Signals portal.
Set your client ID (CID) and API key as environment variables:
export BEHAVIORALSIGNALS_CID="your_cid"
export BEHAVIORALSIGNALS_API_KEY="your_api_key"
The SDK will pick them up automatically:
from behavioralsignals import Client
client = Client()
You can also pass the credentials directly:
client = Client("your_cid", "your_api_key")
Analyze audio
from behavioralsignals import Client
from behavioralsignals.utils import print_results
client = Client()
process = client.behavioral.upload_audio(file_path="audio.wav")
result = client.behavioral.wait_for_result(
pid=process.pid,
timeout=600,
)
print_results(result.results)
upload_audio() returns a process with a unique process ID (pid). wait_for_result() polls until processing completes and returns the analysis result.
print_results() prints one line per result: the start and end time in seconds, the task, and the top label with its probability.
Continuous tasks such as intensity have no label, only a score, and asr and diarization have a label without a probability.
For a 10-second clip of one speaker, the output starts like this:
0.487 3.001 asr The birch canoe slid on the smooth plank.
0.487 3.001 diarization SPEAKER_00
0.487 3.001 language en (98.9%)
0.487 3.001 gender female (99.7%)
0.487 3.001 age 18 - 22 (46.8%)
0.487 3.001 emotion sad (70.6%)
...
0.487 3.001 intensity 0.0873
Each row also has prediction, the list of all labels with their probabilities. Use result.model_dump() to get the results as a dictionary.
To include speaker and behavioral embeddings:
process = client.behavioral.upload_audio(
file_path="audio.wav",
embeddings=True,
)
Deepfake Detection
Audio
Batch deepfake detection follows the same workflow as Behavioral Analysis:
from behavioralsignals import Client
from behavioralsignals.utils import print_results
client = Client()
process = client.deepfakes.upload_audio(file_path="audio.wav")
result = client.deepfakes.wait_for_result(
pid=process.pid,
timeout=600,
)
print_results(result.results)
To include speaker and deepfake embeddings:
process = client.deepfakes.upload_audio(
file_path="audio.wav",
embeddings=True,
)
Experimental Generator Detection
Generator detection is an experimental batch feature that attempts to identify the model used to generate deepfake audio.
process = client.deepfakes.upload_audio(
file_path="audio.wav",
enable_generator_detection=True,
)
See the generator detection documentation for details and supported generators.
Experimental Video Deepfake Detection
Video deepfake detection is available in batch mode only and is currently experimental.
process = client.deepfakes.upload_video(file_path="video.mp4")
result = client.deepfakes.wait_for_video_result(
pid=process.pid,
timeout=600,
)
Unlike an audio result, a video result contains two separate lists:
audio_results— deepfake detection results for the video's audio trackvideo_results— deepfake detection results for the video frames
For example:
print_results(result.video_results)
You can also submit a video using an S3 presigned URL with upload_s3_presigned_video_url() and inspect video processes using list_video_processes() and get_video_process().
See the video deepfake documentation for supported formats, limits, and the current experimental status.
Streaming
Both the Behavioral and Deepfakes APIs support real-time audio streaming over gRPC.
To stream an audio file:
from behavioralsignals import Client, StreamingOptions
from behavioralsignals.utils import make_audio_stream, print_results
client = Client()
audio_stream, sample_rate = make_audio_stream(
"audio.wav",
chunk_size=0.25,
)
options = StreamingOptions(
sample_rate=sample_rate,
encoding="LINEAR_PCM",
)
for result in client.behavioral.stream_audio(
audio_stream=audio_stream,
options=options,
):
print_results(result.results)
chunk_size is specified in seconds, so 0.25 corresponds to 250 ms.
stream_audio() can also accept your own Iterator[bytes], for example from a microphone or live call.
For real-time deepfake detection, use the same interface:
for result in client.deepfakes.stream_audio(
audio_stream=audio_stream,
options=options,
):
print_results(result.results)
See the streaming examples and streaming documentation for more.
Available Methods
client.behavioral and client.deepfakes expose the same methods for audio. Video methods are available only on client.deepfakes.
| Method | What it does |
|---|---|
upload_audio(file_path, ...) |
Uploads an audio file and returns the process, including its pid |
upload_s3_presigned_url(url, ...) |
Submits audio using an S3 presigned URL |
wait_for_result(pid, timeout=None) |
Waits for a process to finish and returns its results |
get_result(pid) |
Returns the results of a finished process |
get_process(pid) |
Returns a process and its current status |
list_processes(...) |
Lists audio processes |
stream_audio(audio_stream, options) |
Streams audio and yields results as they arrive |
upload_video(file_path, ...) |
Deepfakes only: uploads a video file |
upload_s3_presigned_video_url(url, ...) |
Deepfakes only: submits video using an S3 presigned URL |
wait_for_video_result(pid, timeout=None) |
Deepfakes only: waits for a video process to finish and returns its results |
get_video_result(pid) |
Deepfakes only: returns the results of a finished video process |
get_video_process(pid) |
Deepfakes only: returns a video process and its status |
list_video_processes(...) |
Deepfakes only: lists video processes |
behavioralsignals.utils also has two helpers: make_audio_stream(file_path, chunk_size=0.25) turns an audio file into chunks for stream_audio(), and print_results(items) prints result rows as shown in Analyze audio.
For detailed parameters and result schemas, see the full API documentation.
Timeouts and Error Handling
Batch API
Batch HTTP API errors raise BehavioralSignalsError. Its status_code contains the HTTP status code.
from behavioralsignals import BehavioralSignalsError, Client
client = Client()
try:
result = client.behavioral.get_result(pid=12345)
except BehavioralSignalsError as error:
print(error.status_code, error)
wait_for_result() and wait_for_video_result() also raise:
TimeoutErrorif processing has not finished within the suppliedtimeoutRuntimeErrorif the process finishes unsuccessfully, for example because of insufficient credits
Network problems raise the usual requests exceptions, such as requests.ConnectionError.
Each HTTP request also has its own timeout. By default, the SDK allows 10 seconds to connect and up to 60 seconds waiting for the server, or 300 seconds for uploads.
You can customize these limits when creating the client:
client = Client(
timeout=(10, 120),
upload_timeout=(10, 900),
)
These request timeouts are separate from the overall timeout passed to wait_for_result().
If an upload request times out, the server may still have received the file and started processing it. Check
list_processes()— orlist_video_processes()for videos — before uploading the same file again.
Streaming API
Streaming uses gRPC rather than the batch HTTP API. Streaming failures can therefore raise grpc.RpcError instead of BehavioralSignalsError.
import grpc
try:
for result in client.behavioral.stream_audio(
audio_stream=audio_stream,
options=options,
):
... # handle results
except grpc.RpcError as error:
print(error.code(), error.details())
Use with AI Assistants (MCP)
The SDK includes an MCP server (available since version 0.7.0), so AI assistants such as Claude Code, Codex, Claude Desktop, and Cursor can analyze audio and video files for you.
The setups below start the server with uvx, so install uv first.
The server reads credentials from BEHAVIORALSIGNALS_CID and BEHAVIORALSIGNALS_API_KEY. Your assistant starts the server, so provide them in the assistant's MCP configuration as shown below.
Claude Code
With the two variables set in your shell, run:
claude mcp add --env BEHAVIORALSIGNALS_CID="$BEHAVIORALSIGNALS_CID" \
--env BEHAVIORALSIGNALS_API_KEY="$BEHAVIORALSIGNALS_API_KEY" --transport stdio \
behavioralsignals -- uvx --python ">=3.10" --from "behavioralsignals[mcp]" behavioralsignals-mcp
This adds the server to the current project only. Your key stays out of your shell history and out of the repository.
Codex
With the two variables set in your shell, run:
codex mcp add behavioralsignals --env BEHAVIORALSIGNALS_CID="$BEHAVIORALSIGNALS_CID" \
--env BEHAVIORALSIGNALS_API_KEY="$BEHAVIORALSIGNALS_API_KEY" \
-- uvx --python ">=3.10" --from "behavioralsignals[mcp]" behavioralsignals-mcp
This adds the server for all your projects in ~/.codex/config.toml.
Claude Desktop and Cursor
Add this to claude_desktop_config.json (Claude Desktop: Settings > Developer > Edit Config) or ~/.cursor/mcp.json:
{
"mcpServers": {
"behavioralsignals": {
"command": "uvx",
"args": [
"--python",
">=3.10",
"--from",
"behavioralsignals[mcp]",
"behavioralsignals-mcp"
],
"env": {
"BEHAVIORALSIGNALS_CID": "your_cid",
"BEHAVIORALSIGNALS_API_KEY": "your_api_key"
}
}
}
}
If the app cannot find uvx, use its full path (which uvx).
MCP Tools
The server exposes four tools:
| Tool | What it does |
|---|---|
analyze_behavior |
Uploads an audio file or S3 presigned URL for behavioral analysis and returns the results |
detect_deepfake |
Uploads an audio or video file, or an S3 presigned URL, for deepfake detection and returns the results |
get_result |
Returns the results of a process, in pages, optionally filtered to specific tasks |
list_processes |
Lists processes, newest first, including the failure reason when available |
Notes:
- Each upload uses API credits, and files named in MCP tool calls are sent to the Behavioral Signals API.
- Upload tools wait up to
wait_seconds(45 seconds by default, 50 seconds at most). If processing takes longer, they return the process ID so the assistant can check it later withget_result. - Do not commit configuration files containing your API key.
Running the MCP Server Manually
With uv installed, run the server without installing the package:
uvx --python ">=3.10" --from "behavioralsignals[mcp]" behavioralsignals-mcp
Or install the MCP extra with pip:
pip install "behavioralsignals[mcp]"
behavioralsignals-mcp
Requirements
- Python 3.10+
- A Behavioral Signals account and API key
ffmpeg is needed by make_audio_stream() for formats other than WAV, such as mp3.
Documentation and Examples
- Python SDK Documentation
- Full API Documentation
- Streaming with the Python SDK
- Video Deepfake Detection
- Batch Examples
- Streaming Examples
- AI-friendly Documentation (
llms.txt)
Contributing
Contributions are welcome. See CONTRIBUTING.md for development setup, testing, formatting, and pull request guidelines.
Please report security issues according to SECURITY.md.
License
Licensed under the Apache License 2.0. See LICENSE.
Metadata
Release files for behavioralsignals 0.7.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| behavioralsignals-0.7.1.tar.gz | 47.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| behavioralsignals-0.7.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 84.2 kB
Release files / behavioralsignals-0.7.1.tar.gz
| Download URL | behavioralsignals-0.7.1.tar.gz |
|---|---|
| Size | 47.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8c366a64f19c9757844a5175d9f96895105098657369040132fd0d082f6b3b8d
|
|
BLAKE2b-256 checksum How to use checksums |
7fdc23ad416e1ff178afc2364b26a656db14ae1015ef9272807fe86f0b5e30be
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logRelease files / behavioralsignals-0.7.1-py3-none-any.whl
| Download URL | behavioralsignals-0.7.1-py3-none-any.whl |
|---|---|
| Size | 37.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3a00e34f6cb8a59c4832e9d8ed2b4121be033d968abfc7170bc1f37a1abeaf64
|
|
BLAKE2b-256 checksum How to use checksums |
aa23a8fc07c43cafde767e2107c10e860287f8cfb66ccb4a0dced8bdbad6a78d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency log