Quick answer: Create an Enhanced Input Action bound to F8, handle it in your PlayerController’s SetupInputComponent, capture a screenshot before opening the report widget, and include game state metadata (current level, player coordinates, save slot, session ID) in the report. Pause single-player when the widget opens; freeze input but keep simulation running in multiplayer.
The gap between “a player saw a bug” and “the player submitted a report” is enormous. Most players who notice a bug never report it because the friction is too high: leave the game, open a browser, find your form, describe the issue, upload a screenshot they’ve already lost. A single-key hotkey inside the game collapses that entire funnel. Here’s how to add one to your Unreal Engine project properly.
Choose a Key That Doesn’t Conflict
Pick a key that no gameplay mechanic uses and that players won’t press by accident. F8 is a strong default — it’s rarely bound to game actions, it’s easy to reach, and many engines use it for debug screenshots so players already associate it with diagnostics. F12 is another option but conflicts with Steam’s built-in screenshot key.
For controllers, avoid binding to a single face or shoulder button. Use a combination like holding View and pressing D-Pad Up. This prevents accidental triggers during fast gameplay and signals to the player that this is a deliberate action, not a gameplay input.
Create the Enhanced Input Action
In the Content Browser, right-click and create a new Input Action. Name it IA_ReportBug and set its Value Type to Digital (bool). Open your primary Input Mapping Context (usually IMC_Default) and add the new action with F8 as the trigger.
If you have a separate IMC_MenuOnly context for menus, also add the action there so players can report bugs from menus and loading screens, not just gameplay. Don’t add it to contexts that are active during cutscenes unless you want players to report cinematic bugs, in which case you’ll need to handle the pause differently.
Bind the Action in C++ or Blueprint
Here’s the C++ approach for binding the action in your PlayerController:
// MyPlayerController.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "InputActionValue.h"
#include "MyPlayerController.generated.h"
class UInputMappingContext;
class UInputAction;
class UBugReportWidget;
UCLASS()
class MYGAME_API AMyPlayerController : public APlayerController
{
GENERATED_BODY()
protected:
virtual void SetupInputComponent() override;
virtual void BeginPlay() override;
UPROPERTY(EditDefaultsOnly, Category = "Input")
TObjectPtr<UInputMappingContext> DefaultMappingContext;
UPROPERTY(EditDefaultsOnly, Category = "Input")
TObjectPtr<UInputAction> ReportBugAction;
UPROPERTY(EditDefaultsOnly, Category = "UI")
TSubclassOf<UBugReportWidget> BugReportWidgetClass;
void OnReportBugPressed(const FInputActionValue& Value);
};
// MyPlayerController.cpp
#include "MyPlayerController.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "BugReportWidget.h"
#include "Blueprint/UserWidget.h"
#include "Engine/LocalPlayer.h"
#include "Engine/GameViewportClient.h"
#include "UnrealClient.h"
void AMyPlayerController::BeginPlay()
{
Super::BeginPlay();
if (auto* LocalPlayer = Cast<ULocalPlayer>(Player))
{
if (auto* Subsystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
{
Subsystem->AddMappingContext(DefaultMappingContext, 0);
}
}
}
void AMyPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
if (auto* EIC = Cast<UEnhancedInputComponent>(InputComponent))
{
EIC->BindAction(ReportBugAction, ETriggerEvent::Started,
this, &AMyPlayerController::OnReportBugPressed);
}
}
void AMyPlayerController::OnReportBugPressed(const FInputActionValue& Value)
{
// Capture screenshot before opening widget
if (GEngine && GEngine->GameViewport)
{
FScreenshotRequest::RequestScreenshot(TEXT("bug_report_capture"),
/*bShowUI=*/ false,
/*bAddUniqueSuffix=*/ true);
}
// Open the widget
if (BugReportWidgetClass)
{
if (auto* Widget = CreateWidget<UBugReportWidget>(this, BugReportWidgetClass))
{
Widget->AddToViewport(100);
// Pause and unlock mouse in single-player
if (!GetWorld()->IsNetMode(NM_Client))
{
SetPause(true);
}
bShowMouseCursor = true;
SetInputMode(FInputModeUIOnly());
}
}
}
Capture Meaningful Context
The difference between a useful bug report and a useless one is context. Before showing the widget, gather everything you can about the current game state and stash it for submission:
FBugReportContext UBugReportWidget::GatherContext() const
{
FBugReportContext Ctx;
if (auto* PC = GetOwningPlayer())
{
if (auto* Pawn = PC->GetPawn())
{
Ctx.PlayerLocation = Pawn->GetActorLocation().ToString();
Ctx.PlayerRotation = Pawn->GetActorRotation().ToString();
}
Ctx.CurrentLevel = GetWorld()->GetMapName();
Ctx.WorldTimeSeconds = GetWorld()->GetTimeSeconds();
}
// Frame rate over the last second
Ctx.AverageFPS = 1.0f / FApp::GetDeltaTime();
// GPU / driver
Ctx.GPUBrand = FPlatformMisc::GetPrimaryGPUBrand();
Ctx.CPUBrand = FPlatformMisc::GetCPUBrand();
// Session ID should be generated at game start
Ctx.SessionID = FApp::GetSessionName();
// Game version
Ctx.BuildVersion = FEngineVersion::Current().ToString();
return Ctx;
}
Attach this context as metadata when the player submits the report. The triage team now knows what level the bug happened on, where the player was standing, what frame rate they were getting, and what hardware they’re running. That’s the difference between “stuck in the wall” and “stuck in wall at /Game/Maps/L_Forest.umap at coords (1204, 8910, 180) on Nvidia RTX 3060 at 42 FPS.”
Testing the Hotkey
Test in both PIE and a packaged build. PIE behavior differs from packaged for input handling — especially for the pause state and the screenshot capture. In PIE, SetPause sometimes pauses the editor itself; in a packaged build, it pauses the game as expected. Always validate the final flow in a shipped build.
Also verify that the hotkey doesn’t fire while a text input is focused. If a player is typing in your in-game chat and presses F8, you probably don’t want the bug dialog to open — they were trying to type “f8” literally. Check for focused text widgets in the handler and return early.
Communicating the Hotkey to Players
A bug report hotkey only works if players know it exists. Add a brief mention in your options menu (a non-interactive row like “Press F8 to report a bug”) and in your in-game help screen. Don’t waste tutorial time on it, but don’t hide it either. Developers of closed betas should put it in a pinned Discord message and in the title screen footer.
Related Issues
If your Enhanced Input action isn’t firing at all, see Fix: Unreal Enhanced Input Action Not Triggering. For widget visibility issues, see Fix: Unreal UMG Widget Not Showing on Screen. For general input debugging in Unreal, check Fix: Unreal Enhanced Input Not Responding.
The cheapest way to 2x your bug reports is one keybinding. Do it.