CEF-powered Web UI + local WebSocket stack for Unreal Engine, with an external Host.exe renderer process.

This plugin is split into 5 runtime modules:
CefWebUi- Browser session API, shared-memory IPC, input/control writers, frame reader, Slate browser surface.
CefWebSocketServer- Local websocket server subsystem with threaded pipeline and pluggable payload codecs.
CefProtobuf- Binary websocket envelope/codec helpers intended for protobuf-based payloads.
CefDispatch- Format-agnostic
MessageType(uint32) -> Factoryregistry (works with protobuf or any custom type).
- Format-agnostic
CefContentHttpServer- Local HTTP image endpoint (
/img) with pluggable request handler strategy.
- Local HTTP image endpoint (
This plugin requires the external CEF host package (renderer process + CEF runtime files).
Download host package from:
After download, place host files into:
Plugins/CefWebUi/Source/ThirdParty/Cef
Expected key files in that folder:
Host.exelibcef.dll- CEF resources (
*.pak,*.dat,*.bin,locales/, etc.)
If Host.exe is missing or misplaced, runtime startup will fail.
- UE starts
Host.exe. - Host renders Chromium off-screen.
- Host publishes frame metadata + shared GPU textures through IPC/shared resources.
- UE reads frame metadata and copies shared textures into its render path.
- UE forwards mouse/keyboard and control commands (URL, JS, resize, etc.) back to host.
Data/control path:
- Frame stream: Host -> UE
- Input/control stream: UE -> Host
- Optional console stream: Host -> UE logs/events
- Copy plugin into your project:
YourProject/Plugins/CefWebUi
- Put host package into:
YourProject/Plugins/CefWebUi/Source/ThirdParty/Cef
- Enable plugin in
.uproject:
"Plugins": [
{
"Name": "CefWebUi",
"Enabled": true
}
]- Generate project files
- Build project
Use Blueprint function library:
GetCefWebUiSubsystemGetOrCreateBrowserSessionShowBrowserSessionInViewport
Minimal flow:
ShowBrowserSessionInViewportSessionId = "Default"(or your own name)BrowserWidth,BrowserHeight
- Get returned
UCefWebUiBrowserSession. - Call
SetUrl("https://your-page"). - Optional controls:
ExecuteJsReloadResizeSetFocus
If you have a blueprint screenshot for onboarding, add it here:
#include "Subsystems/CefWebUiGameInstanceSubsystem.h"
#include "Sessions/CefWebUiBrowserSession.h"
void UMyGameInstance::InitWebUi()
{
UCefWebUiGameInstanceSubsystem* subsystem = GetSubsystem<UCefWebUiGameInstanceSubsystem>();
if (!subsystem)
{
return;
}
UCefWebUiBrowserSession* session = subsystem->GetOrCreateSession(FName(TEXT("MainUi")), nullptr);
if (!session)
{
return;
}
session->ShowInViewport(/*PlayerController*/ nullptr, /*ZOrder*/ 10, /*Width*/ 1920, /*Height*/ 1080);
session->SetUrl(TEXT("https://example.com"));
session->SetFocus(true);
}Control examples:
session->ExecuteJs(TEXT("console.log('hello from ue');"));
session->Resize(1600, 900);
session->Reload();
session->OpenDevTools();CefProtobuf gives a ready binary envelope/codec layer for websocket payloads where:
- payloads are binary, not plain JSON text,
- message routing is done with typed envelope metadata (for example message type ids),
- protobuf serialization/deserialization is desired.
Use it when you want compact, schema-based transport between UE and browser/backend.
CefDispatch solves routing/creation of typed runtime objects from message ids:
- Register factory per
uint32 MessageType. - Decode inbound bytes by message type.
- Return any value type (
protobuf object, custom struct,FString, raw wrapper, etc.).
This keeps transport and business object creation decoupled.
Typical pattern for binary protocol:
- Websocket codec (
CefProtobuf) extracts envelope:MessageType, payload bytes.
- Dispatch registry (
CefDispatch) usesMessageTypefactory:- parse payload into desired object.
- Application consumes typed value.
This supports both:
- fully protobuf messages
- mixed payload ecosystem (protobuf + custom binary/text)
CefWebSocketServer provides local server lifecycle through subsystem.
Basic usage:
- Get
UCefWebSocketSubsystem. - Build
FCefWebSocketServerCreateOptions(NameId,RequestedPort, pipeline config). - Call
CreateOrGetServer(...). - Bind events:
OnClientConnectedOnClientDisconnectedOnServerErrorOnClientError
- Send:
SendToClientString/BytesBroadcastString/Bytes
Custom transport logic:
- Implement
ICefWebSocketPacketCodecfor your format. - Switch payload mode to
Custom.
CefContentHttpServer is started/stopped by UCefContentHttpServerSubsystem lifecycle.
Default:
- Port:
18080 - Route:
GET /img - Default handler:
- Resolve
assetfrom query/body. - Load texture via module image cache.
- Encode texture to PNG.
- Return
image/png.
- Resolve
Example request:
http://localhost:18080/img?asset=/Game/Folder/T_Image
If your file is:
Content/Folder/T_Image.upackage
then request path should be:
/Game/Folder/T_Image
The module normalizes to object path internally (/Game/Folder/T_Image.T_Image).
Body alternatives:
- JSON body:
{"asset":"/Game/Folder/T_Image"} - Raw body:
asset=/Game/Folder/T_Image
Create custom handler:
#include "Handlers/CefContentHttpImageRequestHandler.h"
#include "MyCustomImageHandler.generated.h"
UCLASS()
class UMyCustomImageHandler : public UCefContentHttpImageRequestHandler
{
GENERATED_BODY()
public:
virtual bool HandleImageRequest_Implementation(
const FCefContentHttpImageRequestContext& InRequestContext,
FCefContentHttpImageResponse& OutResponse,
FString& OutError) override
{
// custom logic...
OutResponse.StatusCode = 200;
OutResponse.ContentType = TEXT("application/json");
const FString payload = TEXT("{\"ok\":true}");
FTCHARToUTF8 utf8(*payload);
OutResponse.Body.Append(reinterpret_cast<const uint8*>(utf8.Get()), utf8.Length());
return true;
}
};Assign handler class through subsystem:
#include "Subsystems/CefContentHttpServerSubsystem.h"
void UMyGameInstance::InitHttpHandler()
{
if (UCefContentHttpServerSubsystem* subsystem = GetSubsystem<UCefContentHttpServerSubsystem>())
{
subsystem->SetRequestHandlerClass(UMyCustomImageHandler::StaticClass(), true);
}
}Project Settings includes Cef Web UI section:
bShowHostConsole- Opens host process with visible console window.
HostAdditionalArgs- Extra command-line args passed to
Host.exe.
- Extra command-line args passed to
Use these for diagnostics and host runtime tuning.
- Verify
Host.exeexists at:Plugins/CefWebUi/Source/ThirdParty/Cef/Host.exe
- Verify CEF runtime files are beside it.
- Confirm host package version matches plugin IPC expectations.
- Check UE logs for shared memory/handle open failures.
- Ensure URL loading actually happens (
SetUrl,LoadHtmlString).
- Ensure session is visible and focused (
SetFocus(true)). - Verify no overlay widget is swallowing mouse/keyboard input.
- Verify resize/input mapping flow if you changed viewport sizing behavior.
- Ensure payload format and codec match on both ends.
- If using protobuf, validate envelope/message type mapping.
- Run minimal browser session in viewport.
- Load local simple HTML first (then remote URL).
- Bind
OnFinishedLoadingand JS console messages. - Add websocket server only after browser path is stable.
- Add protobuf envelope/dispatch routing last.
- Do not edit
ThirdPartyheaders as part of plugin logic changes. - Keep host package in
Source/ThirdParty/Cefconsistent across machines. - If IPC structs/events are changed, UE and host must be updated together.
Project is licensed under MIT