Resources

Get VoicePatrol running in minutes!

Unity Engine

  1. Download: the VoicePatrol Unity package from your project's Set up tab on the dashboard.
  2. Import the package: Assets > Import Package > Custom Package..., then select the package.
  3. Add the prefab for your voice chat to your start scene, and paste your API key into it: VoicePatrol_Photon for Photon Voice, VoicePatrol_Vivox for Vivox, or VoicePatrol_UnityExample for any other voice chat, or none. With VoicePatrol_UnityExample the SDK records the microphone; adapt VoicePatrolUnityExample.cs to your voice chat.
  4. Start VoicePatrol after the player logs in, with their unique ID and display name (below). With VoicePatrol_UnityExample, pass them in its StartVoicePatrol method instead.
  5. Muting: turn on Enable Automated Muting in the prefab, or handle flagged events yourself (below).

VoicePatrolBase.Instance.Initialize(playerId, displayName);

VoicePatrolWrapper.OnViolationDetected += e =>
{
    if (e.Severity >= VoicePatrolWrapper.Severity.High) MutePlayer(e.UniqueId);
};

Upgrading from 3.0? Import 3.1 over your VoicePatrol folder, and replace SetMetadata with SetDisplayName. See the Unity SDK tab for details.

Unreal Engine

  1. Download: the VoicePatrol Unreal plugin from your project's Set up tab on the dashboard.
  2. Install the plugin: close the editor, and extract the zip into your project's Plugins folder (create one at the project root if you don't have one).
  3. Start VoicePatrol after the player logs in: Get Game Instance → Get Subsystem (Voice Patrol Subsystem) → Start Voice Patrol, with your API key and the player's Unique ID. Call Set Display Name too, to show the player's name on the dashboard.
  4. Connect your voice chat: with EOS voice or Vivox, turn on Disable Microphone, then call Attach To Voice Chat. With no voice chat SDK (Windows, Android), leave the microphone on, and call Set Muted (false) while other players can hear the player.
  5. Results: bind On Violation Detected to act on flagged events.
  6. Press Play: with Widget Enabled on, the debug widget shows the SDK's status and each result on screen.

Upgrading from 2.5.6? Start Voice Patrol has new pins (Session ID is gone, and Headless Mode is now Disable Microphone), and results carry findings and a severity. The Unreal SDK tab covers the Online Subsystem EOS, the EOS SDK, consoles and upgrading.

Server-to-server

Voice servers send players' audio straight to VoicePatrol, so the game client sends none.

Photon

  1. Create the plugin: in the Photon dashboard, select Manage on your Voice app, then Create VoicePatrol Plugin.
  2. Configure it: set ApiKey to your API key and IsActive to true, then save.

Vivox

  1. Open Recording: in Unity Gaming Services, open Vivox Recording, then Edit configuration.
  2. Point it at VoicePatrol: set Destination URL to wss://audiom.voicepatrol.dev:6443/ws/vivox, and API key to your API key.
Match the player's ID: when the player logs in to Photon (Client.UserId) or Vivox (PlayerId), use the same unique ID you use for them in your game. Audio is matched to players by this ID, so a mismatch breaks callbacks and splits their history on the dashboard.

Custom voice servers

Running your own voice servers? The server kit sends each player's audio to VoicePatrol from your servers. Download it from your project's Set up tab (Server-to-server → Custom). The Server-to-server tab covers integration.

Getting results, choose one or both

  • Webhooks, no game code: turn on Event Forwarding in the External API tab, and flagged events are sent to your backend.
  • In-game callbacks and muting (Photon and Vivox): add the Unity Photon or Vivox prefab with Headless Mode on, or start the Unreal plugin with Disable Microphone on. No audio is sent from the game.

VoicePatrol doesn't mute players by itself. Use Enable Automated Muting in the Unity prefab, or mute players in your game or backend when a flagged event arrives.

Introduction

VoicePatrol moderates voice chat in multiplayer games in real time. The Unity SDK detects speech on the player's device, uploads only speech, and returns moderation results to your game within seconds. Every event also appears on your dashboard.

What's new in 3.1

  • Display names: the name other players see is shown with every event on the dashboard, in results and in webhooks.
  • Rooms: OnJoinedRoom sets the room shown with each event, and OnLeftRoom now clears it.
  • Severity names: severities are now Low, High and Critical (formerly Medium, High and Severe). Their values are unchanged.
  • Player reports can include the display name the reporter saw for the offender.
  • SetMetadata and the useCdn parameter have been removed. See Upgrading to 3.1 below.

Real-time Voice Moderation

Automatically detect hate, threats, sexual content, harassment and other harmful speech, and act on it in game.

Player Reporting

Let players report others, with the last 2 minutes of audio as evidence for review on your dashboard.

Age Verification

Optionally estimate a player's age range from their first 60 seconds of speech.

Works With Your Voice Chat

Ready-made prefabs for Photon Voice and Vivox, a server-to-server mode where your voice provider sends the audio, and PushAudio for any other voice engine.

Installation & Setup

Requirements

  • Unity 2022.3 or later
  • Windows x64 and x86
  • macOS 10.15 or later on Intel, and 11 or later on Apple silicon (one universal library)
  • Linux x64 with glibc 2.34 or later
  • Android arm64-v8a and armeabi-v7a, API level 23 or later
  • Outbound HTTPS (port 443) to api.voicepatrol.dev
  • Microphone permission, unless your voice provider sends the audio (server-to-server)

Installation Steps

  1. Download the VoicePatrol Unity package from your project's Set up tab at dashboard.voicepatrol.dev.
  2. Import it: Assets > Import Package > Custom Package..., then select the package.
  3. Add the prefab for your voice chat to your start scene: VoicePatrol_Photon for Photon Voice, VoicePatrol_Vivox for Vivox, or VoicePatrol_UnityExample for any other voice chat, or none.
  4. Paste your API key into the prefab in the Inspector. The prefab's setup checklist shows what's left to do.
  5. Start VoicePatrol after the player logs in (see Quick Integration).

Upgrading to 3.1

  1. Import the 3.1 package over your existing VoicePatrol folder. Asset IDs haven't changed, so prefabs and scene references keep working.
  2. Replace calls to SetMetadata with SetDisplayName.
  3. If you pass useCdn to StartVoicePatrol, remove that argument. A call that passes it by position still compiles, but every later argument shifts by one.
  4. Optionally, rename Severity.Medium to Severity.Low and Severity.Severe to Severity.Critical. The old names remain as obsolete aliases.
  5. Upgrading from 2.x? Update your violation handler to read findings and a severity instead of labels and a priority (see Moderation Results), and allow HTTPS (port 443) to api.voicepatrol.dev. Port 50051 is no longer used.

Core Concepts

SDK Lifecycle

  1. Start: StartVoicePatrol, or the prefab's Initialize, connects in the background.
  2. Muted: the SDK starts muted, so nothing is moderated or counted toward usage.
  3. Active: unmute while other players can hear the player. The prefabs do this for you from your voice chat's state.
  4. Rooms: OnJoinedRoom and OnLeftRoom tell VoicePatrol which room the player is in, shown with each event.
  5. Shutdown: the SDK cleans up when the application quits.

Audio Processing Pipeline

Microphone or voice chat → speech detection on the device → speech segments uploaded over HTTPS → moderation → result in your game, on the dashboard and by webhook.

The SDK cuts each player's audio at natural pauses and uploads only speech. Silence and background noise never leave the device. A segment is sent at the first pause after 15 seconds of audio, or at 25 seconds, and its result usually follows within a few seconds.

Unique ID and Display Name

The unique ID is the player's stable ID, the same in every session and on every device. Results, the dashboard and player reports all key on it, so don't use anything that changes, and don't use spaces. The display name is the name other players see. It can change, and the player's profile on the dashboard lists every name they have used.

Key Components

  • VoicePatrolWrapper: static methods for every SDK operation, callable from anywhere.
  • VoicePatrol prefabs (VoicePatrolBase): Photon, Vivox and Unity integrations that start the SDK, follow your voice chat's state, and can mute offenders automatically.
  • AudioCaptureProxy: captures the game's mixed audio output for player reports.
  • Permission manager: requests microphone permission on Android, and degrades gracefully when it's denied.

Quick Integration

1. Add the prefab and your API key

Drag the prefab for your voice chat into your start scene, and paste your API key in the Inspector. The prefab persists across scenes.

2. Start VoicePatrol after the player logs in

Pass the player's unique ID and display name:

VoicePatrolBase.Instance?.Initialize(playerId, displayName);

// Later, if the player changes their name
VoicePatrolBase.Instance?.SetDisplayName(newDisplayName);

Without a prefab, start the SDK from the wrapper, and unmute it while other players can hear the player:

VoicePatrolWrapper.SetDisplayName(displayName);
string status = VoicePatrolWrapper.StartVoicePatrol(apiKey, playerId);
Debug.Log($"VoicePatrol: {status}");

VoicePatrolWrapper.SetMuted(false);

3. Act on results

Turn on Enable Automated Muting in the prefab to mute offenders automatically, with progressive mute rules. Only violations at or above its Minimum Severity (High by default) count. Or handle results yourself:

void OnEnable() => VoicePatrolWrapper.OnViolationDetected += HandleViolation;
void OnDisable() => VoicePatrolWrapper.OnViolationDetected -= HandleViolation;

void HandleViolation(VoicePatrolWrapper.ViolationEventData e)
{
    if (e.Severity >= VoicePatrolWrapper.Severity.High)
        MutePlayer(e.UniqueId);

    foreach (VoicePatrolWrapper.Finding finding in e.Findings)
        Debug.Log($"{e.DisplayName} ({e.UniqueId}): {finding.Category}, " +
                  $"{VoicePatrolWrapper.SeverityName(finding.Severity)}, event {e.EventId}");
}

4. Tell VoicePatrol about rooms

The prefabs pass their voice room's name for you. Otherwise:

VoicePatrolWrapper.OnJoinedRoom(roomId); // on joining a voice room or match
VoicePatrolWrapper.OnLeftRoom(); // on leaving it

API Reference

All methods are static on VoicePatrolWrapper.

StartVoicePatrol

public static string StartVoicePatrol(
    string token,
    string uniqueID = null,
    bool ageVerification = false,
    bool disableMicrophone = false,
    bool debugLogs = false)

Parameters:

  • token: your project's API key from the dashboard.
  • uniqueID: the player's stable unique ID. Defaults to the device ID. No spaces.
  • ageVerification: estimate the player's age from their first 60 seconds of speech.
  • disableMicrophone: don't open the microphone, because the audio comes from your voice engine (PushAudio) or your voice provider's servers (server-to-server).
  • debugLogs: log SDK details to the Unity console.

Returns: a status message. The SDK connects in the background, and starts muted.

SetDisplayName

public static void SetDisplayName(string displayName)

Sets the name other players see, shown with each event on the dashboard and in results, webhooks and player reports. Call it at any time, before or after StartVoicePatrol, and again when the name changes. Null or empty clears it, and names over 64 characters are cut. With a prefab, use VoicePatrolBase.Instance.SetDisplayName.

SetMuted / IsMuted

public static string SetMuted(bool value)
public static bool IsMuted()

Pauses (true) or resumes (false) moderation. While muted, nothing is moderated or counted toward usage. Unmute while other players can hear the player, and mute in menus, single player and loading screens. SetMuted is cheap, so you can call it often.

With a prefab, call VoicePatrolBase.Instance.SetForceMuted(true) instead. The prefab re-evaluates the mute state every second, and would revert a direct SetMuted call. Voice chat keeps working while moderation is paused.
OnJoinedRoom / OnLeftRoom

public static string OnJoinedRoom(string roomId)
public static string OnLeftRoom()

Sets the room shown with each event, such as a voice channel or match ID, and clears it on leaving. Audio after OnLeftRoom has no room until the next OnJoinedRoom.

OnViolationDetected

public static event Action<ViolationEventData> OnViolationDetected;

Raised for each flagged event. ViolationEventData has:

  • UniqueId: the player's unique ID.
  • EventId: the event's ID on the dashboard and in webhooks.
  • DisplayName and RoomId: the player's display name and room when they spoke, or null when unknown.
  • Findings: each has a Category (string) and a Severity.
  • Severity: the highest severity among the findings. Act on this.

Your game receives flagged events only: High and Critical by default, which you can change in the dashboard's Moderation settings.

SubmitPlayerReport

public static string SubmitPlayerReport(
    string offenderID,
    string reason,
    string offenderDisplayName = null)

Uploads the last 120 seconds of everything the local player said and heard as evidence, for review on your dashboard. offenderDisplayName is the name the reporter saw for the offender. The reporter's own display name is included when one is set.

PushAudio

public static void PushAudio(float[] audioData, int length, int sampleRate, int channels)

Feeds audio from your voice engine, such as its outgoing stream, instead of the microphone. Only works when the SDK was started with disableMicrophone: true.

ProcessAudioFile

public static string ProcessAudioFile(AudioClip audioClip)

Sends a recorded clip through moderation or age verification, to test your integration without speaking. The clip must be uncompressed, or set to Decompress On Load.

GetInputDevices / SetInputDevice

public static InputDeviceInfo[] GetInputDevices()
public static string SetInputDevice(string deviceName)
public static string GetCurrentInputDevice()

Lists the microphones (each with a Name and IsDefault), and switches the one the SDK records from. An empty name reverts to the system default. Not available on Android, or with the microphone disabled.

OnAgeVerified

public static event Action<AgeVerificationData> OnAgeVerified;

With age verification on, raised with the player's UniqueId and an estimated MinAge and MaxAge.

IsSdkRunning / StopVoicePatrol

public static bool IsSdkRunning()
public static string StopVoicePatrol()

StopVoicePatrol releases the SDK. Only call it when you're done with moderation altogether. To pause, use SetMuted.

Voice Engine Integration

Add the prefab for your voice chat. It follows your voice chat's state, moderating the player while they're in a voice room and transmitting, and pausing otherwise.

Photon Voice

Add VoicePatrol_Photon to your start scene, and call Initialize after the player logs in. The prefab follows the Photon Voice room and passes its name to VoicePatrol.

VoicePatrolBase.Instance?.Initialize(playerId, displayName);

Vivox

Add VoicePatrol_Vivox to your start scene, and call Initialize after the player logs in. The prefab follows the Vivox channel and passes its name to VoicePatrol.

VoicePatrolBase.Instance?.Initialize(playerId, displayName);

Server-to-server (Photon or Vivox)

Your voice provider's servers send players' audio straight to VoicePatrol, so the game client sends none. Set it up in the Photon or Vivox dashboard (see the Server-to-server tab). For results and automated muting in game as well, turn on Headless Mode in the Photon or Vivox prefab.

Match the player's ID: set Photon's Client.UserId or Vivox's PlayerId to the same unique ID you pass to Initialize. Audio is matched to players by this ID.
Other voice chat, or none

Use VoicePatrol_UnityExample, and adapt VoicePatrolUnityExample.cs to your voice chat. With no voice chat SDK, the SDK records the microphone: unmute it while other players can hear the player. To moderate exactly what your voice engine sends, start with the microphone disabled and push its audio:

VoicePatrolWrapper.StartVoicePatrol(apiKey, playerId, disableMicrophone: true);

// From your voice engine's outgoing audio callback
VoicePatrolWrapper.PushAudio(samples, samples.Length, sampleRate, channels);

Moderation Results

Severity

  • 1 Low (named Medium before 3.1)
  • 2 High
  • 3 Critical (named Severe before 3.1)

Make decisions on severity. To display one, use VoicePatrolWrapper.SeverityName(severity), because the obsolete aliases share values.

Categories

Categories are strings, such as hate, threat, sexual, minors, doxxing, self_harm and custom. VoicePatrolWrapper.Categories lists the common ones, but new categories can appear without an SDK update, so use them for display, reports and appeals rather than for decisions.

Webhooks

To receive flagged events on your backend, turn on Event Forwarding in your project's External API tab on the dashboard. Each event includes the player's unique ID, display name, room, categories and severity.

Best Practices

  • Use a stable unique ID, such as your account or platform user ID, so each player keeps one history on the dashboard.
  • Set the display name whenever it changes, so moderators see who the player appeared as.
  • Pause with SetMuted, or SetForceMuted with a prefab, not StopVoicePatrol.
  • Pause in menus, single player and private rooms, so players are never moderated when nobody can hear them. The prefabs can skip rooms whose name contains a private-room identifier.
  • Unsubscribe from events when your component is destroyed.

void OnDestroy()
{
    VoicePatrolWrapper.OnViolationDetected -= HandleViolation;
    VoicePatrolWrapper.OnAgeVerified -= HandleAgeVerified;
}

void OnApplicationPause(bool paused)
{
    if (paused) VoicePatrolWrapper.SetMuted(true);
}

Troubleshooting

No results

  • Check that the SDK is unmuted: it starts muted.
  • Check the API key, and that the prefab's setup checklist is complete.
  • Check that HTTPS (port 443) to api.voicepatrol.dev is allowed.
  • On Android, check that microphone permission was granted.
  • Low events don't reach your game by default. Every event, including Low ones, appears on the dashboard within seconds.

Debug logs

Start with debug logs on, or turn on Debug Logs in the prefab, to see initialization, audio devices, uploads, results and authentication errors in the console.

VoicePatrolWrapper.StartVoicePatrol(apiKey, playerId, debugLogs: true);

Audio clip processing fails

Set the clip's Load Type to Decompress On Load in its import settings.

Platform-Specific Notes

Android

  • API level 23 or later, arm64-v8a and armeabi-v7a.
  • Microphone permission is requested automatically, unless the microphone is disabled.
  • Compatible with 16 KB page sizes.

Windows, macOS and Linux

  • Windows x64 and x86, macOS 10.15 or later (Intel) and 11 or later (Apple silicon), and Linux x64 with glibc 2.34 or later.
  • Each native library is enabled only for its own platform, so 32-bit Windows builds work.

Introduction

VoicePatrol moderates voice chat in multiplayer games in real time. The Unreal plugin moderates what your players say in voice chat, uploads only speech, and returns results to your game within seconds. Every event also appears on your dashboard.

What's new in 3.1

Plugin 3.1 is the first 3.x release for Unreal, and follows straight on from 2.5.6.

  • Voice chat integration: moderate the voice your game's voice chat sends (EOS voice, Vivox, or any other) with Attach To Voice Chat or Push Audio, instead of opening the microphone twice.
  • Consoles: on PlayStation, Xbox, Switch and other platforms, the plugin builds the SDK from source with your engine's toolchain.
  • HTTPS through the engine: every request goes through Unreal's HTTP module, so your project's proxy, certificate and network settings apply.
  • Findings and severity: results carry findings, each with a category and severity, instead of labels.
  • Display names and rooms are shown with every event on the dashboard, in results and in webhooks.
  • Severity names: Low, High and Critical (formerly Medium, High and Severe).
  • Speech only: silence and background noise never leave the device.

Real-time Voice Moderation

Automatically detect hate, threats, sexual content, harassment and other harmful speech, and act on it in game.

Multi-platform Support

Windows and Android with prebuilt libraries, and PlayStation, Xbox, Switch, Linux, Mac and iOS from source.

Works With Your Voice Chat

EOS voice, Vivox, the EOS SDK directly, or any voice chat that can hand over its audio.

Installation & Setup

Requirements

  • Unreal Engine 5
  • Windows x64 or Android arm64-v8a (API level 23 or later) with the prebuilt library, or any other platform with a source build
  • Outbound HTTPS (port 443) to api.voicepatrol.dev
  • Your project's API key from the dashboard

Installation Steps

  1. Download the VoicePatrol Unreal plugin from your project's Set up tab at dashboard.voicepatrol.dev.
  2. Close the editor, then extract the zip into your project's Plugins folder, so you have Plugins/VoicePatrolSDK. Create the Plugins folder at the project root if you don't have one.
  3. Open the project. Unreal builds the plugin with it.
  4. Verify: on Windows and Android, the Output Log shows LogVoicePatrol: VoicePatrolSDK: All required SDK exports resolved.

Upgrading from 2.5.6

  1. Close the editor, delete your project's Plugins/VoicePatrolSDK folder, and extract the 3.1 zip into Plugins.
  2. Update your StartVoicePatrol call: SessionID and VoiceBI are gone, DeviceID is now UniqueID, and HeadlessMode is now DisableMicrophone. In Blueprints, reconnect the Start Voice Patrol node's new pins.
  3. Update your violation handler: results now carry findings and a severity instead of labels (see Moderation Results).
  4. In C++, rename EVoicePatrolSeverity::Medium to Low and Severe to Critical. Blueprints update themselves.
  5. Optionally, set the player's display name with SetDisplayName, and their room with OnJoinedRoom.
  6. If your network allowlists VoicePatrol, allow HTTPS (port 443) to api.voicepatrol.dev. Port 50051 is no longer used.

Core Concepts

How Audio Reaches VoicePatrol

  • EOS voice (EOSVoiceChat plugin) or Vivox: call Attach To Voice Chat.
  • The Online Subsystem EOS: call AttachToVoiceChatUser from C++.
  • The EOS SDK directly, or another voice chat: push its audio with PushAudioPcm16 or Push Audio.
  • No voice chat SDK (Windows and Android only): the plugin opens the microphone itself.

On consoles, use your voice chat. The plugin's own microphone capture isn't available there.

Audio Processing Pipeline

Voice chat or microphone → speech detection on the device → speech segments uploaded over HTTPS → moderation → result in your game, on the dashboard and by webhook.

The SDK cuts each player's audio at natural pauses and uploads only speech. A segment is sent at the first pause after 15 seconds of audio, or at 25 seconds, and its result usually follows within a few seconds.

Unique ID and Display Name

The unique ID is the player's stable ID, the same in every session and on every device. Results, the dashboard and player reports all key on it, so don't use anything that changes, and don't use spaces. The display name is the name other players see. It can change, and the player's profile on the dashboard lists every name they have used.

Key Components

  • UVoicePatrolSubsystem: a Game Instance subsystem, and the interface for every SDK operation. Get it with GetGameInstance()->GetSubsystem<UVoicePatrolSubsystem>(), or Get Game Instance → Get Subsystem (Voice Patrol Subsystem) in Blueprints. Results are delivered on the game thread.
  • FVoicePatrolSDKModule: loads the SDK at startup. IsReady() says whether it loaded.
  • UVoicePatrolBlueprintLibrary: Blueprint helpers for testing.

API Reference

All functions are on UVoicePatrolSubsystem, and the Blueprint nodes have the same names.

UVoicePatrolSubsystem* VoicePatrol = GetGameInstance()->GetSubsystem<UVoicePatrolSubsystem>();

StartVoicePatrol

void StartVoicePatrol(FString Token, FString UniqueID, bool AgeVerification,
                      bool DisableMicrophone, bool LogsEnabled, bool WidgetEnabled);

Parameters:

  • Token: your project's API key from the dashboard.
  • UniqueID: the player's stable unique ID. Pass an empty string to use a generated, persisted device ID. No spaces.
  • AgeVerification: estimate the player's age from their first 60 seconds of speech.
  • DisableMicrophone: don't open the microphone, because the audio comes from your voice chat (AttachToVoiceChat, PushAudio) or your voice provider's servers. Required on consoles.
  • LogsEnabled: verbose SDK logs in the Output Log.
  • WidgetEnabled: show the in-game debug widget.

The SDK connects in the background.

SetDisplayName

void SetDisplayName(FString DisplayName) const;

Sets the name other players see, shown with each event on the dashboard and in results and webhooks. Call it at any time, before or after StartVoicePatrol, and again when the name changes.

AttachToVoiceChat / DetachFromVoiceChat

bool AttachToVoiceChat();
bool AttachToVoiceChatUser(IVoiceChatUser* VoiceChatUser);
void DetachFromVoiceChat();

Moderates the voice your voice chat sends, using Unreal's voice chat interface (EOS voice or Vivox). The player is moderated while they're in a voice channel, and the channel name is used as the room. Start the SDK with DisableMicrophone first. AttachToVoiceChatUser attaches a specific voice chat user, such as the Online Subsystem EOS user.

PushAudio / PushAudioSamples / PushAudioPcm16

void PushAudio(const TArray<float>& Samples, int32 SampleRate, int32 Channels) const;
static void PushAudioSamples(const float* Samples, int32 NumSamples, int32 SampleRate, int32 Channels);
static void PushAudioPcm16(const int16* Samples, int32 NumSamples, int32 SampleRate, int32 Channels);

Feeds audio from any voice chat, from any thread. Use with DisableMicrophone, together with SetMuted and the room functions.

SetMuted / SetForceMuted

void SetMuted(bool IsMuted);
bool IsMuted() const;
void SetForceMuted(bool ForceMuted);
bool IsForceMuted() const;

With voice chat attached, SetForceMuted(true) pauses moderation, for example in private rooms, and voice chat keeps working. SetMuted has no effect while attached.

With the plugin's microphone, or audio you push, the SDK starts muted. Call SetMuted(false) while other players can hear the player, and SetMuted(true) in menus and single player. SetMuted can be called before StartVoicePatrol.

OnJoinedRoom / OnLeftRoom

void OnJoinedRoom(FString RoomID) const;
void OnLeftRoom() const;

Sets the room shown with each event, such as a voice channel or match ID, and clears it. AttachToVoiceChat does both for you.

GetInputLevel / IsMicrophoneDisabled

float GetInputLevel() const;
bool IsMicrophoneDisabled() const;

GetInputLevel shows whether audio is arriving, from the microphone or pushed audio.

ProcessAudioFile

FString ProcessAudioFile(const TArray<float>& AudioData, int32 SampleRate, int32 Channels) const;

Sends recorded float PCM audio through moderation, to test your integration without speaking. Returns a status message.

GetInputDevices / SetInputDevice

TArray<FVoicePatrolInputDevice> GetInputDevices() const;
void SetInputDevice(FString DeviceName) const;
FString GetCurrentInputDevice() const;

Lists the microphones (each with a Name and bIsDefault), and switches the one the plugin records from. An empty name reverts to the system default. Only with the plugin's own microphone, and not on Android.

IsSDKRunning / StopVoicePatrol

bool IsSDKRunning() const;
void StopVoicePatrol();

StopVoicePatrol releases the SDK. Only call it when you're done with moderation altogether. To pause, use SetMuted or SetForceMuted.

Moderation Results

Bind On Violation Detected in Blueprints, or OnInfractionIdentified() in C++. Each result is one FVoicePatrolViolation:

  • UniqueId: the player's unique ID.
  • EventId: the event's ID on the dashboard and in webhooks.
  • DisplayName and RoomId: the player's display name and room when they spoke, empty when unknown.
  • Findings: each has a Category (string) and a Severity.
  • Severity: the highest severity among the findings. Act on this.

VoicePatrol->OnInfractionIdentified().AddLambda([](const FVoicePatrolViolation& Violation)
{
    if (Violation.Severity >= EVoicePatrolSeverity::High)
    {
        MutePlayer(Violation.UniqueId);
    }
    for (const FVoicePatrolFinding& Finding : Violation.Findings)
    {
        UE_LOG(LogTemp, Log, TEXT("%s: %s, event %s"),
            *Violation.UniqueId, *Finding.Category, *Violation.EventId);
    }
});

Severity

  • 1 Low (named Medium before 3.1)
  • 2 High
  • 3 Critical (named Severe before 3.1)

Your game receives flagged events only: High and Critical by default, which you can change in the dashboard's Moderation settings.

Categories

Categories are strings, such as hate, threat and sexual. VoicePatrolCategories lists the common ones, but new categories can appear without a plugin update, so make decisions on severity, and use the category for display, reports and appeals.

Webhooks

To receive flagged events on your backend, turn on Event Forwarding in your project's External API tab on the dashboard.

Voice Engine Integration

Moderate the voice your game's voice chat sends: what other players actually hear. This avoids capturing the microphone twice, and it's how the plugin works on consoles.

EOS voice or Vivox (quick start)

Once the player is logged in to voice chat, from your Game Instance or anywhere you can reach it:

  1. Get Game Instance → Get Subsystem (Voice Patrol Subsystem)
  2. Set Display Name (optional)
  3. Start Voice Patrol with your API key, the player's Unique ID, and Disable Microphone on
  4. Attach To Voice Chat

UVoicePatrolSubsystem* VoicePatrol = GetGameInstance()->GetSubsystem<UVoicePatrolSubsystem>();
VoicePatrol->SetDisplayName(PlayerName);
VoicePatrol->StartVoicePatrol(ApiKey, PlayerId, /*AgeVerification*/ false,
    /*DisableMicrophone*/ true, /*LogsEnabled*/ false, /*WidgetEnabled*/ false);
VoicePatrol->AttachToVoiceChat();

VoicePatrol then follows your voice chat automatically.

Online Subsystem EOS

The Online Subsystem EOS keeps a voice chat user per player. Attach that user from C++:

#include "IOnlineSubsystemEOS.h"
#include "OnlineSubsystem.h"

IOnlineSubsystemEOS* EOS = static_cast<IOnlineSubsystemEOS*>(IOnlineSubsystem::Get(EOS_SUBSYSTEM));
VoicePatrol->AttachToVoiceChatUser(EOS->GetVoiceChatUserInterface(*LocalUserId));

The EOS SDK directly

Push the audio EOS is about to send, and tell VoicePatrol when the player joins and leaves a voice room:

EOS_RTCAudio_AddNotifyAudioBeforeSendOptions Options = {};
Options.ApiVersion = EOS_RTCAUDIO_ADDNOTIFYAUDIOBEFORESEND_API_LATEST;
Options.LocalUserId = LocalUserId;
Options.RoomName = RoomName;
EOS_RTCAudio_AddNotifyAudioBeforeSend(RTCAudioHandle, &Options, nullptr,
    [](const EOS_RTCAudio_AudioBeforeSendCallbackInfo* Data)
    {
        const EOS_RTCAudio_AudioBuffer* Buffer = Data->Buffer;
        UVoicePatrolSubsystem::PushAudioPcm16(Buffer->Frames,
            Buffer->FramesCount * Buffer->Channels, Buffer->SampleRate, Buffer->Channels);
    });

// On joining the voice room
VoicePatrol->OnJoinedRoom(UTF8_TO_TCHAR(RoomName));
VoicePatrol->SetMuted(false);
// On leaving it
VoicePatrol->SetMuted(true);
VoicePatrol->OnLeftRoom();

Other voice chat

Start with Disable Microphone on, and push the audio your voice chat sends with Push Audio (Blueprint, float samples), PushAudioSamples or PushAudioPcm16, from any thread. Call SetMuted(false) while the player is transmitting in a voice room, and use OnJoinedRoom and OnLeftRoom.

No voice chat SDK (Windows and Android)

Leave Disable Microphone off, and the plugin records the microphone. It starts muted: call Set Muted (false) while other players can hear the player, and Set Muted (true) in menus and single player.

Server-to-server (Photon or Vivox)

Your voice provider's servers send players' audio straight to VoicePatrol (see the Server-to-server tab). For results in game as well, start the plugin with Disable Microphone on, and don't attach or push audio.

Match the player's ID: use the same unique ID for the player in your voice provider as in StartVoicePatrol. Audio is matched to players by this ID.

Advanced Features

Consoles and Other Platforms

Windows and Android use the prebuilt library in Libs/. On every other platform, including PlayStation, Xbox and Switch, the plugin compiles the SDK from the source in Source/ThirdParty/VoicePatrolCore with your engine's toolchain, using the engine's own Opus, Ogg and HTTP modules. Those builds have no microphone capture, so start with Disable Microphone and attach your voice chat. If you don't, StartVoicePatrol disables the microphone itself and logs a warning. Console support is new in 3.1, so please let us know how your first console build goes.

Age Verification

With AgeVerification on, VoicePatrol estimates the player's age range from their first 60 seconds of speech. Bind On Age Verified in Blueprints, or OnAgeClassificationReceived() in C++:

VoicePatrol->OnAgeClassificationReceived().AddLambda([](uint32 MinAge, uint32 MaxAge)
{
    if (MaxAge <= 12) EnableChildSafetyMode();
    else if (MaxAge <= 15) EnableTeenSafetyFeatures();
    else EnableFullFeatures();
});

Testing Your Integration

  • Turn on Widget Enabled in Start Voice Patrol to see the SDK's status and each result on screen.
  • Send a recording through VoicePatrol with the console command VoicePatrol.TestModerationWithRecording <path to a WAV file>, or the Test Moderation With Sound Wave Blueprint node.
  • Every event, including Low ones your game doesn't receive, appears on the dashboard within seconds.

Best Practices

  • Use a stable unique ID, such as your EOS Product User ID or account ID, so each player keeps one history on the dashboard.
  • Set the display name whenever it changes, so moderators see who the player appeared as.
  • Prefer your voice chat over the plugin's microphone, so you moderate exactly what other players hear.
  • Pause with SetForceMuted or SetMuted, not StopVoicePatrol.
  • Unbind delegates when your object ends play.

void AYourGameMode::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
    if (UVoicePatrolSubsystem* VoicePatrol = GetGameInstance()->GetSubsystem<UVoicePatrolSubsystem>())
    {
        VoicePatrol->OnInfractionIdentified().RemoveAll(this);
        VoicePatrol->OnAgeClassificationReceived().RemoveAll(this);
    }
    Super::EndPlay(EndPlayReason);
}

Troubleshooting

SDK doesn't start

On Windows and Android, look for All required SDK exports resolved in the Output Log at startup. If it's missing, check that the plugin's Libs/ folder has the library for your platform, and that you extracted the 3.1 zip into a clean Plugins/VoicePatrolSDK folder.

No results

  • With voice chat attached, check that the player is in a voice channel and transmitting, and isn't force muted.
  • With the plugin's microphone or pushed audio, check that SetMuted(false) was called: the SDK starts muted.
  • Check that audio is arriving with GetInputLevel, or the debug widget.
  • Check that HTTPS (port 443) to api.voicepatrol.dev is allowed, including your project's HTTP proxy settings.
  • Low events don't reach your game by default. Check the dashboard, which shows every event.

Debug logs

VoicePatrol->StartVoicePatrol(ApiKey, PlayerId, false, true, /*LogsEnabled*/ true, /*WidgetEnabled*/ true);

Platform notes

  • Android: arm64-v8a, API level 23 or later, compatible with 16 KB page sizes.
  • Windows: x64. The library is staged in packaged builds automatically.
  • Consoles, Linux, Mac and iOS: source build, with voice chat audio only.
  • Dedicated servers: the plugin doesn't run there, and builds for them without the voice chat interface.

Introduction

With server-to-server moderation, your voice provider's servers or your own voice servers send players' audio straight to VoicePatrol. Nothing runs on the game client, so it works on every platform you ship to.

Choose Your Setup

  • Photon Voice: add the VoicePatrol plugin to your Photon Voice app.
  • Vivox: point Vivox real-time recording at VoicePatrol in Unity Gaming Services.
  • Your own voice servers: use the VoicePatrol server kit, a small C library for Linux and Windows.

Getting Results, Choose One or Both

  • Webhooks, no game code: turn on Event Forwarding in your project's External API tab, and flagged events are sent to your backend.
  • In-game callbacks and muting (Photon and Vivox): add the Unity Photon or Vivox prefab with Headless Mode on, or start the Unreal plugin with Disable Microphone on. No audio is sent from the game.

VoicePatrol doesn't mute players by itself. Use Enable Automated Muting in the Unity prefab, or mute players in your game or backend when a flagged event arrives.

Match the player's ID: audio is matched to players by their unique ID. Use the same stable ID for the player in your voice provider or voice servers as in your game, or callbacks won't match and their history splits on the dashboard.

Photon

  1. Create the plugin: in the Photon dashboard, select Manage on your Voice app, then Create VoicePatrol Plugin.
  2. Configure it: set ApiKey to your VoicePatrol API key and IsActive to true, then save.
  3. Match the player's ID: when the player logs in to Photon, set Client.UserId to the unique ID you use for them in your game. Photon allows this before joining a room.

For results in a Unity game, add the VoicePatrol_Photon prefab with Headless Mode on, and call Initialize with the same ID:

VoicePatrolBase.Instance?.Initialize(playerId, displayName);

Vivox

  1. Open Recording: in Unity Gaming Services, open Vivox Recording, then Edit configuration.
  2. Point it at VoicePatrol: set Destination URL to the address below, and API key to your VoicePatrol API key.
  3. Match the player's ID: when the player logs in to Vivox, set their PlayerId to the unique ID you use for them in your game.

wss://audiom.voicepatrol.dev:6443/ws/vivox

For results in a Unity game, add the VoicePatrol_Vivox prefab with Headless Mode on. In Unreal, start the plugin with Disable Microphone on.

Server Kit

Running your own voice servers? The server kit gives each talking player a handle, and you push their audio into it, as the Opus packets your server already relays or as PCM. It runs the same speech detection and segmenting as the VoicePatrol SDK on game clients: it keeps only speech, cuts each player's audio at natural pauses, and encodes and uploads it, with retries. Results come back to you by webhook.

Download it from your project's Set up tab on the dashboard (Server-to-server → Custom).

Contents

  • include/voicepatrol_server.h: the C API, with every call documented.
  • lib/linux-x86_64/libVoicePatrol_Server.so: Linux, glibc 2.34 or later.
  • lib/windows-x64/VoicePatrol_Server.dll and .lib: Windows, for development.
  • example/stream_wav.c: streams WAV files as if each were a player talking.
  • The library carries its own HTTPS client and audio codecs, and needs no other libraries.

Integration

#include "voicepatrol_server.h"

vp_server_config config = {0};
config.api_key = "..."; /* your VoicePatrol API key */
config.log = my_log_function; /* optional */
vp_server* vp = vp_server_create(&config);

/* A player starts talking in a room */
vp_player* p = vp_player_open(vp, unique_id, room_id);
vp_player_set_display_name(p, display_name); /* optional */

/* For every voice packet you receive from them */
vp_player_push_opus(p, packet, packet_length);

/* They released push-to-talk, or their client stopped sending */
vp_player_gap(p);

/* They moved rooms, or left */
vp_player_set_room(p, new_room_id);
vp_player_close(p);

/* Shutting down: send what's left, then stop */
vp_server_drain(vp, 30000);
vp_server_destroy(vp);

  • Unique ID: your stable ID for the player, the same in every session. If your game client also uses the VoicePatrol SDK, for example for player reports, pass it the same ID.
  • Display name: optional, shown with each of the player's events on the dashboard and in webhooks. Call it again if the name changes. Names over 64 characters are cut.
  • Audio: vp_player_push_opus takes Opus packets exactly as your clients send them, at any frame size, sample rate or channel count. vp_player_push_pcm takes 16-bit PCM at any rate. 16 kHz mono is cheapest.
  • Threads: pushing only runs speech detection, which takes microseconds. Encoding and uploads run on the kit's own threads. Calls for one player must not overlap; different players can be fed from different threads.
  • Rooms: optional, shown with each of the player's events.

Trying It

export VOICEPATROL_API_KEY=your-key
./stream_wav --player-prefix test-player- --display-name "Test Player" speech.wav other-speech.wav

Each file becomes a player. Use a file with a violation in it, and its result arrives at your webhook within seconds.

How Audio Is Processed

  1. Speech detection: audio is decoded to 16 kHz mono and checked in 20 ms frames. The detector looks at speech frequencies rather than loudness, so fans, music and breathing rarely trigger it.
  2. Onset: a segment opens after 60 ms of continuous speech, and keeps the 300 ms before it, so the first word arrives whole.
  3. Silence: pauses inside a segment are kept, but shortened to 1 second. Audio between segments is dropped, so a silent player uploads nothing.
  4. Cut: once a segment holds at least 15 seconds of audio and 3 seconds of speech, it is cut at the next pause, so sentences stay whole. At 25 seconds it is cut regardless.
  5. Encoding: each segment is encoded as Ogg/Opus at 24 kbit/s, about 75 KB for 25 seconds, and uploaded.

Uploads and Errors

  • No response, a timeout or a 5xx: the kit retries the same segment after backoff. VoicePatrol never moderates a segment twice.
  • 429 (usage limit): audio is dropped for the period the response gives.
  • 400 or 413: that segment is dropped.
  • 401 or 403: uploads stop and an error is logged. Check the API key and the subscription.

If uploads can't keep up, up to max_backlog_minutes of audio waits (60 by default), and the oldest is dropped beyond that. vp_server_get_stats returns counts of segments cut, uploaded, retried, rejected and dropped, for your metrics.

Webhooks

Open your project's settings on the dashboard, go to the External API tab, and turn on Event Forwarding. Enter your endpoint's URL, and set a webhook secret so you can verify each request. Each project forwards its own results.

Only flagged events are forwarded. The flag thresholds in the Moderation tab decide what's flagged in each category. Each request carries a batch of up to 100 results:

{
  "organization_id": "6f1c...",
  "timestamp": "2026-10-28T03:12:45Z",
  "data": [
    {
      "id": "0d3e...",
      "project_id": "9a2b...",
      "unique_id": "player-123",
      "display_name": "Sparky",
      "room_id": "lobby-7",
      "categories": ["hate"],
      "severity_level": 3,
      "severity_label": "critical",
      "transcription": "...",
      "timestamp": "2026-10-28T03:12:44Z"
    }
  ]
}

  • display_name and room_id are the ones the player had when they spoke, and are left out when unknown.
  • severity_level is 1 (low), 2 (high) or 3 (critical). Act on the number: the labels may change.
  • Webhooks set up before SDK 3.1 keep the legacy format until you switch them in the dashboard: the same fields, plus device_id and severity (medium, high or severe).

Verify Every Request

X-VoicePatrol-Signature is sha256= followed by the hex HMAC-SHA256, keyed with your webhook secret, of X-VoicePatrol-Timestamp + "." + the raw request body. Reject requests whose timestamp is more than 5 minutes from your clock, and compare signatures in constant time:

import hashlib, hmac, time

def verify(secret: bytes, timestamp: str, body: bytes, signature: str) -> bool:
    if abs(time.time() - int(timestamp)) > 300:
        return False
    expected = "sha256=" + hmac.new(secret, timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

Sizing

Encoding is most of the cost. One core of an Intel i9-13900K handles about 220 players talking continuously, including decoding their Opus packets. A typical cloud vCPU is roughly half as fast. Silence isn't encoded, so players who talk part of the time cost proportionally less.

  • One encoder thread is the default. Raise encoder_threads if vp_server_get_stats shows the queue growing while uploads are healthy.
  • Upload bandwidth is about 3 KB/s per talking player.
  • Need to build from source, port the kit to another platform, or call the HTTP API directly? Contact us.

Frequently Asked

General

Why is real-time response necessary?

Delays can allow harmful behavior to escalate, leading to poor user experiences and increased churn. VoicePatrol’s real-time detection addresses issues instantly—typically within 30 seconds—minimizing harm to your community.

Is VoicePatrol compatible with my platform or game engine?

Yes. VoicePatrol has SDKs for Unity and Unreal Engine (including console builds), a native SDK for custom engines, and a server-to-server option for Photon Voice, Vivox or your own voice servers.

Setup and Functionality

How easy is it to set up VoicePatrol?

VoicePatrol is designed for rapid integration. In Unity or Unreal, setup takes a few minutes and only a handful of calls, with only minimal back-end support needed. Server-to-server setups need no changes to your game client at all.

Does VoicePatrol store all data?

We store the audio of only the most severe violations for 60 days.

Can I customize filtering settings?

Yes, VoicePatrol allows custom settings for toxicity categories, severity levels, and automated responses to align with your platform’s needs.

Is VoicePatrol fully automated?

Yes, our AI fully automates the detection process, reducing the need for human moderation and lowering operational costs.

Product Benefits and Impact

How does VoicePatrol reduce churn and boost revenue?

By filtering out harmful interactions, VoicePatrol creates a positive community experience, leading to happier, more engaged users. Platforms report a 24% reduction in churn and an 11% boost in revenue after one quarter.

What kind of insights does VoicePatrol provide?

The web-based dashboard provides data on flagged incidents, severity levels, and community health trends, enabling long-term management and improvement.

How does VoicePatrol compare to other tools?

VoicePatrol offers competitive pricing, fast integration, and real-time filtering across multiple formats without a monthly minimum, unlike many alternatives.

Can VoicePatrol support high-traffic platforms?

Yes, VoicePatrol scales to manage large volumes of interactions, making it ideal for high-traffic platforms.

Industry Standards and Data

What percentage of users experience harmful interactions?

Studies show 80% of players encounter toxicity online, with 67% avoiding certain spaces due to these interactions.

How does proactive filtering improve user experience?

Proactive filtering like VoicePatrol’s reduces harm immediately, creating a more positive environment and boosting user satisfaction and trust.

Why is filtering critical for brand reputation?

Unchecked harmful behavior can damage a platform’s image. Filtering keeps spaces safe and inclusive, contributing to positive brand sentiment and user loyalty.

Are there legal risks without content filtering?

New laws, such as the California Kids Code, impose fines on platforms that fail to manage harmful interactions. VoicePatrol helps reduce PR and legal risks.

Trial and Support

Is there a free trial for VoicePatrol?

Yes, new users can try VoicePatrol with 500 free audio hours to test its impact.

Does VoicePatrol offer integration support?

Absolutely, we offer customer support during setup and a demo to walk you through features, customization, and integration.

Can I see VoicePatrol in action before committing?

Yes, book a demo to explore VoicePatrol’s functionality and see how it fits your needs.

Still have questions?

Get Your Free Audit Today

Not sure how toxic your game is, how many voice-hours you have or how much this would cost?
Get a 2-week free audit.

Get 2-week free audit
no credit card required
Book a demo
Dark futuristic armor with neon green glowing circuit lines on a black background.
back
up