# Add Audio Moderation

This how-to guide shows you **how to build real-time audio moderation** into a Stream Video call using the Stream Python AI SDK and the Stream Moderation API.

For a complete runnable example, see the [GitHub sample](https://github.com/GetStream/stream-py/tree/webrtc/examples/audio_moderation).

> Need an overview first? See the [Moderating Video Calls explanation](/video/docs/python-ai/video-features/moderating-video-calls/).

## What You Will Build

A small “moderation bot” that

1. Joins a call as a participant
2. Listens to raw PCM audio from every speaker
3. Transcribes speech with a Speech-to-Text (STT) plugin (in our case, Deepgram)
4. Sends each utterance to the Moderation API
5. Outputs the moderation verdict

> Note: we're using [Deepgram](https://deepgram.com/) as our speech-to-text provider here, but you can use any provider you like.

![The audio moderation worflow as a diagram](@video/python-ai/_assets/guides/add-audio-moderation/overview.png)

## Set Up Your Environment

### Install the SDK and STT Plugin

> Note: we're using [uv](https://docs.astral.sh/uv/) for package/dependency management, but you can use another tool if you prefer.

```bash
uv add getstream>=2.3.0a4 getstream-plugins-deepgram>=0.1.1
```

Create a `.env` file in your project root:

```dotenv
# Stream credentials
STREAM_API_KEY=your_stream_api_key
STREAM_API_SECRET=your_stream_api_secret
EXAMPLE_BASE_URL=https://pronto.getstream.io

# STT provider (example for Deepgram)
DEEPGRAM_API_KEY=your_deepgram_api_key
```

## Initialise the Core Clients

Create a file called `main.py` and add the following content:

```python
from dotenv import load_dotenv
import os, uuid
from getstream.stream import Stream
from getstream.video import rtc
from getstream.plugins.deepgram import DeepgramSTT

load_dotenv()

client = Stream.from_env()   # initialises with STREAM_API_KEY / SECRET
stt = DeepgramSTT()          # uses DEEPGRAM_API_KEY from env
```

## Create Users and Call

```python
call_id = str(uuid.uuid4())
print(f"📞 Call ID: {call_id}")

user_id = f"user-{uuid.uuid4()}"
create_user(client, user_id, "My User")
logging.info("👤 Created user: %s", user_id)

user_token = client.create_token(user_id, expiration=3600)
logging.info("🔑 Created token for user: %s", user_id)

bot_user_id = f"moderation-bot-{uuid.uuid4()}"
create_user(client, bot_user_id, "Moderation Bot")
logging.info("🤖 Created bot user: %s", bot_user_id)

# Create the call
call = client.video.call("default", call_id)
call.get_or_create(data={"created_by_id": bot_user_id})
print(f"📞 Call created: {call_id}")
```

## Create a Moderation Policy Configuration

Create a Moderation policy config with the key `custom:python-ai-test`. The policy below will flag text deemed insulting.

```python
client = Stream.from_env()
client.moderation.upsert_config(
    key="custom:python-ai-test",
    ai_text_config={
        "rules": [{"label": "INSULT", "action": "flag"}],
    },
)
```

> You can also create a moderation policy config from the [Stream dashboard](https://getstream.io/accounts/login/), by creating an app, then navigating to Moderation > Policies > Add New.

![The audio moderation menu in the Stream dashboard](@video/python-ai/_assets/guides/add-audio-moderation/moderation-menu.png)
The audio moderation menu in the Stream dashboard.

![The audio moderation policy page in the Stream dashboard](@video/python-ai/_assets/guides/add-audio-moderation/moderation-policies.png)
The audio moderation policy page in the Stream dashboard.

## Open a Web Browser for Testing

```python
import webbrowser

base_url = f"{os.getenv('EXAMPLE_BASE_URL')}/join/"
params = {"api_key": api_key, "token": user_token, "skip_lobby": "true"}

url = f"{base_url}{call_id}?{urlencode(params)}"
print(f"Opening browser to: {url}")

webbrowser.open(url)
```

This will open your browser and authenticate you as the user you created earlier.

## Add the Moderation Bot and Process Audio

Once the moderation bot is added to the call, it will start listening for audio events emitted by the Python AI SDK. Once it receives an `audio` event, it will transcribe the audio via STT and send a `transcript` event.

```python
from getstream.models import ModerationPayload
import uuid

async with rtc.join(call, bot_user_id) as connection:
    @connection.on("audio")
    async def on_audio(pcm: PcmData, user):
        # Process audio through STT
        await stt.process_audio(pcm, user)
```

## Add the Moderation Check

Add this event handler, which runs when the STT provider sends a `transcript` event.

```python
    @stt.on("transcript")
    async def on_transcript(text: str, user: any, metadata: dict):
        timestamp = time.strftime("%H:%M:%S")
        user_info = user.name if user and hasattr(user, "name") else "unknown"
        print(f"[{timestamp}] {user_info}: {text}")
        if metadata.get("confidence"):
            print(f"    └─ confidence: {metadata['confidence']:.2%}")

        # Moderation check (executed in a background thread to avoid blocking)
        moderation = await asyncio.to_thread(moderate, client, text, user_info)
        print(
            f"    └─ moderation recommended action: {moderation.recommended_action} for transcript: {text}"
        )

    # Keep the connection alive and wait for audio
    await connection.wait()
```

That’s it! Your bot now moderates speech in real-time.

## Run the Code

Run the code with

```python
uv run main.py
```

It will open up a web browser so you can join the call. You will see a bot participant joining. Now you can speak to it and test the moderation features by saying nice or insulting things!

You should see output like the following in your terminal:

An innocent sentence which is reviewed as safe:
![Terminal output of a "non-offensive" sentence, the Moderation API recommends keeping the text and taking no action](@video/python-ai/_assets/guides/add-audio-moderation/moderation-keep.png)

An insulting sentence which is reviewed as potentially infringing the moderation policy:
![Terminal output of an "insult" sentence, the Moderation API recommends flagging the text for review](@video/python-ai/_assets/guides/add-audio-moderation/moderation-flag.png)

## Review the Content

When a sentence is recommended to be flagged by the moderation API, it's also available in the [review queue](https://getstream.io/moderation/docs/api/#query-review-queue). You can access this via the Python SDK or the Dashboard.

Access it via the SDK with

```python
from getstream.models import QueryReviewQueueResponse, ReviewQueueItemResponse

response: QueryReviewQueueResponse = client.moderation.query_review_queue().data
item: ReviewQueueItemResponse

for item in response.items:
    print("--------------------------------")
    print(f"Flagged audio transcript with ID: {item.id}")
    print(f"Recommended action: {item.recommended_action}")
    if item.recommended_action != "keep":
        print(f"Transcript: {item.moderation_payload.texts[0]}")
    print(f"Created at: {item.created_at.isoformat()}")
```

![Terminal output when querying the review queue, containing references to utterances by the speaker](@video/python-ai/_assets/guides/add-audio-moderation/moderation-review-queue.png)
You will then see the items the Moderation API has sent to the review queue.

You can also see and review this content in the Dashboard, as well as doing things like banning and deleting users.

![Screenshot from the Stream dashboard when querying the review queue, containing references to utterances by the speaker](@video/python-ai/_assets/guides/add-audio-moderation/dashboard-review-queue.png)

## Next Steps

- You can find a [full, working example on GitHub](https://github.com/GetStream/stream-py/tree/webrtc/examples/audio_moderation).
- There's much more you can do with the Moderation API! Check out the [Moderation API documentation](https://getstream.io/moderation/docs/)

---

This page was last updated at 2025-08-15T14:16:42.517Z.

For the most recent version of this documentation, visit [https://getstream.io/video/docs/python-ai/guides/add-audio-moderation/](https://getstream.io/video/docs/python-ai/guides/add-audio-moderation/).