Skip to main content

Behavioral Signals API Python SDK

Behavioral Signal Technologies

Discord Twitter readme.io CI Coverage Ruff Checked with mypy uv PyPI Status Downloads Python License Contributor Covenant

Python SDK for the Behavioral Signals API. Behavioral Signals builds AI solutions that understand human behavior through voice and detect deepfake content in audio. Our API enables developers to integrate behavioral analysis into their applications, both in batch and streaming modes. See the API documentation for details. It is also available as llms.txt for AI coding assistants.

Table of Contents

Features

  • Behavioral Analysis API : Analyze human behavior in both batch (offline) and streaming (online) modes.

  • Deepfake Detection API: Detect synthetic or manipulated speech using advanced deepfake detection models.

    • Supports batch (offline) and streaming (online) modes
    • Compatible with a wide range of spoken languages
  • Core Speech Attributes (Batch Only): Extract foundational conversational metadata from both APIs:

    • Automatic Speech Recognition (ASR)
    • Speaker Diarization
    • Language Identification
  • MCP server: Let AI assistants such as Claude and Cursor analyze files for you. See Use with AI assistants (MCP).

Requirements

  • Python3.10+,
  • ffmpeg,
  • Python dependencies as specified in pyproject.toml

API Key Setup

To use the Behavioral Signals API, you need to create an account and obtain an API key from the Behavioral Signals portal.

You can pass your client ID (CID) and API key to Client(YOUR_CID, YOUR_API_KEY), or set them as environment variables and call Client():

export BEHAVIORALSIGNALS_CID=your_cid
export BEHAVIORALSIGNALS_API_KEY=your_api_key

SDK Installation

pip install behavioralsignals

SDK Example Usage

After obtaining your API key, you can use the SDK to interact with the Behavioral Signals APIs. We currently provide two main APIs:

  • the Behavioral API for analyzing human behavior through voice, and
  • the Deepfakes API for detecting deepfake audio content in human speech.

Both APIs support batch and streaming modes, allowing you to send audio files or streams for analysis and receive results after processing and in real-time, respectively. You can also find more detailed examples for both batch and streaming in the examples/ directory.

Behavioral API Batch Mode

In batch mode, you can send audio files to the Behavioral Signals API for analysis. The API will return a unique process ID (PID) that you can use to retrieve the results later. wait_for_result checks the process status until processing is complete, then returns the results (available since version 0.6.0). Pass timeout in seconds to stop waiting after that long; it raises TimeoutError if processing has not finished.

from behavioralsignals import Client

client = Client(YOUR_CID, YOUR_API_KEY)

response = client.behavioral.upload_audio(file_path="audio.wav")
output = client.behavioral.wait_for_result(pid=response.pid, timeout=600)

for item in output.results or []:
    top = item.prediction[0]
    label = item.finalLabel or top.score  # continuous tasks (e.g. intensity) have no label
    if not label:
        continue  # the features row carries embeddings, not a result
    confidence = f" ({float(top.posterior):.1%})" if top.posterior else ""
    print(f"{item.st} {item.et} {item.task} {label}{confidence}")

Each result row has 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 output.model_dump() to get the results as a dictionary.

Setting embeddings=True during audio upload will include speaker and behavioral embeddings in the output (see documentation):

response = client.behavioral.upload_audio(file_path="audio.wav", embeddings=True)
output = client.behavioral.wait_for_result(pid=response.pid, timeout=600)

Each HTTP request also has its own time limit: 10 seconds to connect, then up to 60 seconds of waiting for the server (300 seconds for uploads). You can change these when creating the client, or pass None for no limit:

client = Client(YOUR_CID, YOUR_API_KEY, timeout=(10, 120), upload_timeout=(10, 900))

These limits apply to single requests. The timeout of wait_for_result limits the whole wait. If an upload times out, the server may still have received the file and started a process, so check list_processes() (or list_video_processes() for videos) before uploading again.

Behavioral API Streaming Mode

In streaming mode, you can send audio data in real-time to the Behavioral Signals API. The API will return results as they are processed.

from behavioralsignals import Client, StreamingOptions
from behavioralsignals.utils import make_audio_stream

client = Client(YOUR_CID, YOUR_API_KEY)
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):
    for item in result.results or []:
        top = item.prediction[0]
        label = item.finalLabel or top.score  # continuous tasks (e.g. intensity) have no label
        if not label:
            continue  # the features row carries embeddings, not a result
        confidence = f" ({float(top.posterior):.1%})" if top.posterior else ""
        print(f"{item.st} {item.et} {item.task} {label}{confidence}")

Deepfakes API Batch Mode

A similar example for the Deepfakes API in batch mode allows you to send audio files for deepfake detection:

from behavioralsignals import Client

client = Client(YOUR_CID, YOUR_API_KEY)

response = client.deepfakes.upload_audio(file_path="audio.wav")
output = client.deepfakes.wait_for_result(pid=response.pid, timeout=600)

for item in output.results or []:
    top = item.prediction[0]
    label = item.finalLabel or top.score  # some tasks have no label, only a score
    if not label:
        continue  # the features row carries embeddings, not a result
    confidence = f" ({float(top.posterior):.1%})" if top.posterior else ""
    print(f"{item.st} {item.et} {item.task} {label}{confidence}")

Setting embeddings=True during audio upload will include speaker and deepfake embeddings in the output (see documentation):

response = client.deepfakes.upload_audio(file_path="audio.wav", embeddings=True)
output = client.deepfakes.wait_for_result(pid=response.pid, timeout=600)

🔬 Experimental: Deepfake Generator Prediction (Batch Only)

An experimental option is now available that attempts to predict the generator model used to produce a deepfake. When enabled, the returned results will contain an additional field - only for audios with detected deepfake content - indicating the predicted generator model along with a confidence score.

You can activate this feature by passing enable_generator_detection=True during audio upload:

from behavioralsignals import Client

client = Client(YOUR_CID, YOUR_API_KEY)

response = client.deepfakes.upload_audio(file_path="audio.wav", enable_generator_detection=True)
output = client.deepfakes.wait_for_result(pid=response.pid, timeout=600)

See more in our API documentation.

🎬 Video Deepfake Detection (Batch Only)

In addition to audio, the Deepfakes API can detect deepfakes in video files. You upload a video the same way you upload audio, and the API analyzes both the audio track and the video frames.

from behavioralsignals import Client

client = Client(YOUR_CID, YOUR_API_KEY)

response = client.deepfakes.upload_video(file_path="video.mp4")
output = client.deepfakes.wait_for_video_result(pid=response.pid, timeout=600)

Unlike wait_for_result, the video result response returns two separate lists — audio_results (deepfake detection on the audio track) and video_results (deepfake detection on the video frames):

for item in output.video_results or []:
    top = item.prediction[0]
    label = item.finalLabel or top.score  # some tasks have no label, only a score
    if not label:
        continue  # the features row carries embeddings, not a result
    confidence = f" ({float(top.posterior):.1%})" if top.posterior else ""
    print(f"{item.st} {item.et} {item.task} {label}{confidence}")

You can also submit a video via an S3 presigned URL with client.deepfakes.upload_s3_presigned_video_url(url=...), and list/inspect video processes with client.deepfakes.list_video_processes() and client.deepfakes.get_video_process(pid=...). The embeddings and enable_generator_detection options are supported and apply to the audio-track results. Video deepfake detection is currently available in batch mode only.

Deepfakes API Streaming Mode

A similar streaming example for the Deepfakes API allows you to send audio data in real-time for speech deepfake detection:

from behavioralsignals import Client, StreamingOptions
from behavioralsignals.utils import make_audio_stream

client = Client(YOUR_CID, YOUR_API_KEY)
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.deepfakes.stream_audio(audio_stream=audio_stream, options=options):
    for item in result.results or []:
        top = item.prediction[0]
        label = item.finalLabel or top.score  # some tasks have no label, only a score
        if not label:
            continue  # the features row carries embeddings, not a result
        confidence = f" ({float(top.posterior):.1%})" if top.posterior else ""
        print(f"{item.st} {item.et} {item.task} {label}{confidence}")

Available Methods

client.behavioral and client.deepfakes have the same methods for audio. Video methods are only on client.deepfakes.

Method What it does
upload_audio(file_path, ...) Uploads an audio file and returns the process, with its pid
upload_s3_presigned_url(url, ...) Same as upload_audio, for audio at 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 status
list_processes(page=0, page_size=1000, sort="asc", start_date=None, end_date=None) Lists your processes
stream_audio(audio_stream, options) Sends audio as a stream and yields results as they arrive
upload_video(file_path, ...) Deepfakes only: uploads a video file
upload_s3_presigned_video_url(url, ...) Deepfakes only: same as upload_video, for a video at 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 your video processes

Error Handling

When the API returns an error, the SDK raises BehavioralSignalsError. Its status_code is the HTTP status code. wait_for_result also raises TimeoutError if processing is not done within timeout seconds, and RuntimeError if the process failed (for example, not enough credits).

from behavioralsignals import BehavioralSignalsError, Client

client = Client(YOUR_CID, YOUR_API_KEY)

try:
    output = client.behavioral.get_result(pid=12345)
except BehavioralSignalsError as error:
    print(error.status_code, error)

BehavioralSignalsError is a subclass of Exception, so code that catches Exception keeps working. Network problems raise the usual requests exceptions, such as requests.ConnectionError.

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 your credentials from BEHAVIORALSIGNALS_CID and BEHAVIORALSIGNALS_API_KEY (see API Key Setup). Your assistant starts the server, so set them in the assistant's config, 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 for you in 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 (in Claude Desktop, Settings > Developer > Edit Config) or to ~/.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 (run which uvx to find it).

The server has 4 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 only for some tasks
list_processes Lists your processes, newest first, with the reason when one failed

Notes:

  • Each upload uses credits, and the files you name are sent to the Behavioral Signals API.
  • The upload tools wait up to wait_seconds (45 by default, 50 at most). If processing takes longer, they return the process ID, and the assistant checks it later with get_result.
  • Don't commit config files that contain your API key.

Running the MCP server manually

With uv installed, you can run it without installing anything else:

uvx --python ">=3.10" --from "behavioralsignals[mcp]" behavioralsignals-mcp

Or install it with pip and run behavioralsignals-mcp:

pip install "behavioralsignals[mcp]"

Metadata

Release files for behavioralsignals 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for behavioralsignals 0.7.0
File Size Uploaded
behavioralsignals-0.7.0.tar.gz 47.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for behavioralsignals 0.7.0
File Interpreter ABI Platform
behavioralsignals-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 84.3 kB

Release files / behavioralsignals-0.7.0.tar.gz

Download URL behavioralsignals-0.7.0.tar.gz
Size 47.4 kB
Tags Source
SHA-256 checksum
How to use checksums
90f3171ac968627ac597b1c6afda90a26f4a6aaebf41560aae3a3cfdc00bca61
BLAKE2b-256 checksum
How to use checksums
34379fab0a7803f5c568af62afd57387175283d7c4a5cae02a6c7d289c73b16e
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 22, 2026.

Transparency log

Release files / behavioralsignals-0.7.0-py3-none-any.whl

Download URL behavioralsignals-0.7.0-py3-none-any.whl
Size 37.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bc7b81e51060e2c281371f9977f4b0377fac209c9dd47e93cfe54418c3457c87
BLAKE2b-256 checksum
How to use checksums
2ba7ecf282c4bf97ab416076e7ed05c709bcf0e9802022977e8bc471a04d8b0b
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 22, 2026.

Transparency log

Release history Release notifications | RSS feed

0.7.1

2 release files

This release

0.7.0 This release

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page