Skip to content

Custom Chat Integration

Verité normally filters messages automatically. However, some chat plugins intercept Minecraft's normal chat event and handle message delivery themselves.

If your plugin does this, Verité may never receive the original message to filter. In that case, you should pass the message through Verité before your plugin sends it.

You only need this guide if your plugin handles or replaces normal Minecraft chat. Servers using standard chat do not need any additional setup.

Java Integration

Verité provides a small public API specifically for integrations like custom chat systems.

1. Add Verité as a soft dependency

Add Verité to your plugin.yml:

softdepend:
  - Verite

Using a soft dependency ensures Verité loads before your integration when installed, without making it mandatory for your plugin to start.

2. Check whether the API is available

If Verité is optional, check for the API before using it:

private static final boolean VERITE_AVAILABLE;

static {
    boolean available;

    try {
        Class.forName("teacommontea.api.VeriteFilter");
        available = true;
    } catch (ClassNotFoundException ignored) {
        available = false;
    }

    VERITE_AVAILABLE = available;
}

Your integration can then simply do nothing when Verité isn't installed.

3. Filter the message

Before your custom chat system sends a message, pass it to VeriteFilter:

if (VERITE_AVAILABLE) {
    FilterResult result = VeriteFilter.check(
        player.getUniqueId(),
        message
    );

    if (result.blocks()) {
        player.sendMessage(VeriteFilter.blockMessage());
        return;
    }
}

That's all that is required for a basic integration.

check() runs the message through Verité's filter and records the flag against the player. If .blocks() returns true, your chat system should prevent the message from being sent.

Using the filter category

Sometimes you'll want to know why Verité caught a message:

FilterResult result = VeriteFilter.check(
    player.getUniqueId(),
    message
);

switch (result) {
    case CLEAN -> {
        // Send normally
    }

    case SELF_HARM, ABUSE -> {
        // Handle appropriately
    }

    default -> {
        // Ordinary blocked content
    }
}

The possible results are:

  • CLEAN
  • BLOCK
  • PROFANITY
  • SELF_HARM
  • ABUSE

Anything except CLEAN returns true from .blocks().

Important: SELF_HARM and ABUSE exist so these messages can be handled differently from ordinary rule violations. We recommend against automatically treating them as punishable chat offenses.

Detecting repeated messages

If your chat system needs to distinguish filtered content from repeat-message detection, use the repeat-aware overload:

FilterOutcome outcome = VeriteFilter.check(
    player.getUniqueId(),
    message,
    true
);

if (outcome.blocks()) {
    if (outcome.repeat()) {
        player.sendMessage(VeriteFilter.repeatMessage());
    } else {
        player.sendMessage(VeriteFilter.blockMessage());
    }

    return;
}

outcome.category() provides the normal filter category, while outcome.repeat() tells you whether the message was blocked because it was repeated.

Filtering Other User Content

The API isn't limited to chat.

If your plugin accepts user-written content such as nicknames, prefixes, team tags, or similar fields, you can run those through the same filter:

if (VeriteFilter.check(player.getUniqueId(), nickname).blocks()) {
    // Reject the nickname
}

For text that doesn't belong to a particular player, use VeriteFilter.ANONYMOUS:

FilterResult result = VeriteFilter.check(
    VeriteFilter.ANONYMOUS,
    text
);

Anonymous checks still return the appropriate filter category, but do not add a flag to any player's record.


Using Verité with Skript

If your custom chat system is written in Skript, you don't need to interact with the Java API.

With Verité and Skript installed, Verité's filtering syntax is available automatically.

Filtering Custom Chat

If your script already handles sending chat messages itself, check the message before sending it:

if {_msg} is blocked for player:
    send block message to player
    stop

Including for player tells Verité who sent the message and records the flag against that player.

Without a player:

if {_text} is blocked:
    # Reject the text

Verité performs a pure filter check without recording a flag. This is useful for things such as names, tags, signs, or other text that shouldn't count against a specific player.

Checking Why a Message Was Blocked

For more control, retrieve the filter result:

set {_result} to filter result of {_msg} for player

if {_result} is "self_harm":
    # Handle separately
    stop

if {_result} is "abuse":
    # Handle separately
    stop

if {_result} is not "clean":
    send block message to player
    stop

The result will be one of:

clean, block, profanity, self_harm, or abuse

Important: Consider handling self_harm and abuse separately from ordinary moderation violations rather than automatically punishing the player.

Checking a Player's Flag Count

You can also retrieve the number of messages Verité has flagged for a player:

set {_flags} to message flags of player

This can be used by your own moderation system if you want different behaviour for repeated violations.

Skript Syntax Reference

%string% is blocked [for %-player%]
%string% is not blocked [for %-player%]

filter result of %string% [for %-player%]

block message

message flags of %player%

The optional player matters:

With a player: the filter result is recorded against that player.

Without a player: Verité only checks the text and does not record a flag.


API Reference

The public API is located under:

teacommontea.api

The primary class for chat integrations is:

VeriteFilter

Useful methods include:

VeriteFilter.check(UUID player, String message)
VeriteFilter.check(UUID player, String message, boolean repeatAware)

VeriteFilter.count(UUID player)

VeriteFilter.blockMessage()
VeriteFilter.repeatMessage()
VeriteFilter.selfHarmMessage()

VeriteFilter.blockNotice(FilterResult result, String message)

VeriteFilter.ANONYMOUS can be used when filtering text that isn't associated with a player.

Verité also exposes its normalization utilities for integrations that need them, including accent folding, entity stripping, repeated-character reduction, fingerprinting, and edge trimming. These functions are thread-safe and generally do not need to be called manually before using check().

For most custom chat integrations, all you need is:

if (VeriteFilter.check(player.getUniqueId(), message).blocks()) {
    // Don't send the message
}

Verité handles the rest.