---
title: "Handle reports and sanctions"
description: "Submit player reports and respond to moderation outcomes."
seo:
  noindex: true
---

{/* Copyright (c) 2026 Betide Studio. All Rights Reserved. */}

Keep the reported player's full handle. Reports and sanctions go to the provider that owns that handle; support is not shared across every platform.

## Report a player

**Blueprint**

<BlueprintViewer title="Report a player" src="/blueprints/crossplay-report-player.txt" />

**C++**

Game module dependencies: `UCIKCore`, `BetideCore`.

```cpp
#include "Engine/GameInstance.h"
#include "Platform/UCIKPlatformSubsystem.h"
#include "UCIKCore.h"

void ReportPlayer(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player,
                  const FString &Reason, const FString &MatchId)
{
    auto *Service = GameInstance.GetSubsystem<UUCIKPlatformSubsystem>();
    if (!Service)
        return;

    FUCIK_PlayerReport Report;
    Report.Player = Player;
    Report.Category = EUCIK_ReportCategory::Cheating;
    Report.Message = Reason;
    Report.Context.Add(TEXT("MatchId"), MatchId);
    Service->SendPlayerReport(
        Report,
        FBetideCallback<bool>::CreateWeakLambda(&GameInstance, [](const TBetideResult<bool> &Result) {
            if (!Result.bOk)
            {
                UE_LOG(LogUCIK, Warning, TEXT("%s"), *Result.Error.GetLogString());
                return;
            }
            UE_LOG(LogUCIK, Log, TEXT("Report submitted: %d"), Result.GetValue());
        }));
}
```

Attach useful match details in **Context**. A submitted report is not a ban. Query sanctions separately and let your server decide how each action affects access.

## Check active sanctions

**Blueprint**

<Accordion>
  <AccordionItem title="List player sanctions">
<BlueprintViewer title="List player sanctions" src="/blueprints/crossplay-query-sanctions.txt" />
  </AccordionItem>
  <AccordionItem title="Check active sanctions">
<BlueprintViewer title="Check active sanctions" src="/blueprints/crossplay-check-sanctions.txt" />
  </AccordionItem>
</Accordion>

**C++**

Game module dependencies: `UCIKCore`, `BetideCore`.

```cpp
#include "Engine/GameInstance.h"
#include "Platform/UCIKPlatformSubsystem.h"
#include "UCIKCore.h"

void CheckPlayerSanctions(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player)
{
    auto *Service = GameInstance.GetSubsystem<UUCIKPlatformSubsystem>();
    if (!Service)
        return;

    Service->IsPlayerSanctioned(
        Player,
        FBetideCallback<bool>::CreateWeakLambda(&GameInstance, [](const TBetideResult<bool> &Result) {
            if (!Result.bOk)
            {
                UE_LOG(LogUCIK, Warning, TEXT("%s"), *Result.Error.GetLogString());
                return;
            }
            UE_LOG(LogUCIK, Log, TEXT("Has active sanction: %d"), Result.GetValue());
        }));
}
```

```cpp
void ListPlayerSanctions(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player)
{
    auto *Service = GameInstance.GetSubsystem<UUCIKPlatformSubsystem>();
    if (!Service)
        return;
    Service->QuerySanctions(
        Player, FBetideCallback<TArray<FUCIK_Sanction>>::CreateWeakLambda(
                    &GameInstance, [](const TBetideResult<TArray<FUCIK_Sanction>> &Result) {
                        if (!Result.bOk)
                        {
                            UE_LOG(LogUCIK, Warning, TEXT("%s"), *Result.Error.GetLogString());
                            return;
                        }
                        for (const FUCIK_Sanction &Sanction : Result.GetValue())
                            UE_LOG(LogUCIK, Log, TEXT("%s: %s"), *Sanction.Action,
                                   *Sanction.ReferenceId);
                    }));
}
```

Server kicks require the player’s handle to be reported through `UUCIKPlayerLinkComponent` on their PlayerController. Call the kick from trusted server logic; the host cannot kick itself.

## Block, mute, or remove

**Blueprint**

<Accordion>
  <AccordionItem title="Block a player">
<BlueprintViewer title="Block a player" src="/blueprints/crossplay-block-player.txt" />
  </AccordionItem>
  <AccordionItem title="Unblock a player">
<BlueprintViewer title="Unblock a player" src="/blueprints/crossplay-unblock-player.txt" />
  </AccordionItem>
  <AccordionItem title="List blocked players">
<BlueprintViewer title="List blocked players" src="/blueprints/crossplay-blocked-players.txt" />
  </AccordionItem>
  <AccordionItem title="Save a local mute">
<BlueprintViewer title="Save a local mute" src="/blueprints/crossplay-persistent-mute.txt" />
  </AccordionItem>
  <AccordionItem title="Remove a player from the server">
<BlueprintViewer title="Remove a player from the server" src="/blueprints/crossplay-kick-player.txt" />
  </AccordionItem>
</Accordion>

**C++**

Game module dependencies: `UCIKCore`, `BetideCore`.

<Accordion>

  <AccordionItem title="Block a player">

```cpp
#include "Engine/GameInstance.h"
#include "Social/UCIKSocialSubsystem.h"
#include "UCIKCore.h"

void BlockPlayer(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player)
{
    auto *Service = GameInstance.GetSubsystem<UUCIKSocialSubsystem>();
    if (!Service)
        return;
    Service->BlockPlayer(
        Player,
        FBetideCallback<bool>::CreateWeakLambda(&GameInstance, [](const TBetideResult<bool> &Result) {
            if (!Result.bOk)
            {
                UE_LOG(LogUCIK, Warning, TEXT("%s"), *Result.Error.GetLogString());
                return;
            }
            UE_LOG(LogUCIK, Log, TEXT("Block completed: %d"), Result.GetValue());
        }));
}
```

  </AccordionItem>

  <AccordionItem title="Unblock a player">

```cpp
#include "Engine/GameInstance.h"
#include "Social/UCIKSocialSubsystem.h"
#include "UCIKCore.h"

void UnblockPlayer(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player)
{
    auto *Service = GameInstance.GetSubsystem<UUCIKSocialSubsystem>();
    if (!Service)
        return;
    Service->UnblockPlayer(
        Player,
        FBetideCallback<bool>::CreateWeakLambda(&GameInstance, [](const TBetideResult<bool> &Result) {
            if (!Result.bOk)
            {
                UE_LOG(LogUCIK, Warning, TEXT("%s"), *Result.Error.GetLogString());
                return;
            }
            UE_LOG(LogUCIK, Log, TEXT("Unblock completed: %d"), Result.GetValue());
        }));
}
```

  </AccordionItem>

  <AccordionItem title="List blocked players">

```cpp
#include "Engine/GameInstance.h"
#include "Social/UCIKSocialSubsystem.h"
#include "UCIKCore.h"

void ListBlockedPlayers(UGameInstance &GameInstance)
{
    auto *Service = GameInstance.GetSubsystem<UUCIKSocialSubsystem>();
    if (!Service)
        return;
    Service->GetBlockedPlayers(FBetideCallback<TArray<FUCIK_PlayerHandle>>::CreateWeakLambda(
        &GameInstance, [](const TBetideResult<TArray<FUCIK_PlayerHandle>> &Result) {
            if (!Result.bOk)
            {
                UE_LOG(LogUCIK, Warning, TEXT("%s"), *Result.Error.GetLogString());
                return;
            }
            for (const FUCIK_PlayerHandle &Player : Result.GetValue())
                UE_LOG(LogUCIK, Log, TEXT("%s"), *Player.ToString());
        }));
}
```

  </AccordionItem>
  <AccordionItem title="Save a local mute">

```cpp
#include "Engine/GameInstance.h"
#include "Social/UCIKSocialSubsystem.h"
#include "UCIKCore.h"

void SetPlayerMute(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player, bool bMuted)
{
    if (auto *Service = GameInstance.GetSubsystem<UUCIKSocialSubsystem>())
    {
        Service->SetPlayerMuted(Player, bMuted);
        UE_LOG(LogUCIK, Log, TEXT("Muted: %d"), Service->IsPlayerMuted(Player));
    }
}
```

  </AccordionItem>
  <AccordionItem title="Remove a player from the server">

```cpp
#include "Engine/GameInstance.h"
#include "Platform/UCIKPlatformSubsystem.h"
#include "UCIKCore.h"

void RemovePlayerFromServer(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player,
                            const FText &Reason)
{
    if (auto *Service = GameInstance.GetSubsystem<UUCIKPlatformSubsystem>())
    {
        const FBetideError Error = Service->KickPlayerFromServer(Player, Reason);
        if (Error.IsError())
            UE_LOG(LogUCIK, Warning, TEXT("%s"), *Error.GetLogString());
        else
            UE_LOG(LogUCIK, Log, TEXT("Player removed"));
    }
}
```

  </AccordionItem>
</Accordion>

Blocking, local voice muting, lobby removal, and server kicks are separate actions. Persistent mutes are stored on this machine. A sanction with no expiry is permanent; a failed query must not be treated as a clean record.
