UE5.8 UWebBrowser — Click-through background?

I’m using the native UWebBrowser in UE5.8 for a interactive HTML.

I want clicks on the HTML background to pass through to the game, while buttons and inputs remain interactive, all within a single WebBrowser widget.

CSS pointer-events: none doesn’t seem to help because the WebBrowser still captures the entire widget area. Setting it to Not Hit-Testable (Self & All Children) disables everything.

I also tested the following HTML. The content before <!DOCTYPE html> and after </html> is rendered and selectable, but the area still blocks mouse input to the game. CSS pointer-events doesn’t seem to change this behavior.

<span style="display: inline-block; background-color: pink"> AAA </span>
<!DOCTYPE html>
<html>
<body>
    <div style="background: red; padding: 30px;">
        HTML BODY
    </div>
</body>
</html>
BBB
Click Interaction

Within the AAA, the span:

LogBlueprintUserMessages: [HUD_C_C_0] HTML recibió pointerdown: [object HTMLSpanElement]
LogBlueprintUserMessages: [HUD_C_C_0] HTML recibió click: [object HTMLSpanElement]

Since AAA is a span, I click on “that unknown area” just the same:

LogBlueprintUserMessages: [HUD_C_C_0] HTML recibió pointerdown: [object HTMLBodyElement]
LogBlueprintUserMessages: [HUD_C_C_0] HTML recibió click: [object HTMLBodyElement]

We are inside a HTMLBodyElement.

Inside the red div element:

LogBlueprintUserMessages: [HUD_C_C_0] HTML recibió pointerdown: [object HTMLDivElement]
LogBlueprintUserMessages: [HUD_C_C_0] HTML recibió click: [object HTMLDivElement]
I've made it this far, but it's starting to look like this isn't my fault.
FReply FWebBrowserViewport::OnMouseButtonDown(const FGeometry& *MyGeometry*, const FPointerEvent& *MouseEvent*)

{

    *// Capture mouse on left/middle/right button down so that you can drag out of the viewport*

    FReply Reply = WebBrowserWindow->OnMouseButtonDown(*MyGeometry*, *MouseEvent*, bIsPopup);

    if (*MouseEvent*.GetPressedButtons().Num() == 1 &&

        (*MouseEvent*.GetEffectingButton() == EKeys::LeftMouseButton || *MouseEvent*.GetEffectingButton() == EKeys::MiddleMouseButton || *MouseEvent*.GetEffectingButton() == EKeys::RightMouseButton))

    {

        const FWidgetPath\* Path = *MouseEvent*.GetEventPath();

        if (Path->IsValid())

        {

            TSharedRef<SWidget> TopWidget = Path->Widgets.Last().Widget;

            return Reply.CaptureMouse(TopWidget);

        }

    }

    return Reply;

}

Not Hit-Testable (Self): FWebBrowserViewport::OnMouseButtonDown() executes and reaches Reply.CaptureMouse(TopWidget).

Not Hit-Testable (Self & All Children): execution of the function stops.

Is there a way to make these non-interactive areas pass mouse input through to the game using the native UE5.8 WebBrowser?

The stock UWebBrowser in 5.8 cannot do per-pixel click-through. CSS pointer-events only affects hit testing inside CEF. The Slate widget still owns the whole rectangle and eats the mouse before the game sees it. Not Hit-Testable (Self and All Children) is the other extreme: it turns off the entire widget, including the buttons. There is no middle setting on the native widget. A transparent background and content outside the doctype do not change that. Transparency is only the blend, not the input shape.

What works without an engine change:

  1. Do not cover the screen with one browser. Size and place the WebBrowser widget only over the interactive cluster (the buttons and inputs). Build the non-interactive HUD in UMG, or in a second browser widget set to Not Hit-Testable. Holes in the HTML are not holes in the widget.

  2. If the HTML really has to be full screen, set the WebBrowser to Not Hit-Testable and put UMG controls on top, in the same screen positions as the HTML buttons. Forward those clicks with Execute Javascript. Fragile if the layout moves, but it stays in project code.

If you need real holes in one widget, it is a plugin/engine change, not a project setting. The widget is SWebBrowser / SWebBrowserView. You would override the mouse down / cursor hit test and, from JS, ask document.elementFromPoint whether that pixel is a button or input. If it is not, return FReply::Unhandled() so the game gets the click. CEF will not report that back to Slate on its own, which is why pointer-events looks like it does nothing.

So for 5.8 native WebBrowser: shrink the widget to the interactive area, or split hit-testing into UMG. The single full-screen widget with click-through holes is not supported.

GPT is spot on.
I assume you saw the code I pasted. Although, judging by your reply, it seems you didn’t which screams “pure GPT.” Ask GPT if the code above can be modified to allow the cursor to pass through.

Modifying Slate: check document.elementFromPoint() and return FReply::Unhandled(). Here’s the tricky part: simply returning that result doesn’t guarantee the event reaches the game or that Chromium correctly receives subsequent events. You have to integrate hit-testing, mouse handling, and Slate event capturing.

GPT is going to have to step up its game and fast on this one.

The function I arrived at while debugging and which GPT needs to fix was this one: FReply FWebBrowserViewport::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
Let’s see if GPT can fix this.

Tell GPT for me that it was very bold to say:

If you need real holes in one widget, it is a plugin/engine change, not a project setting. The widget is SWebBrowser / SWebBrowserView. You would override the mouse down / cursor hit test and, from JS, ask document.elementFromPoint whether that pixel is a button or input. If it is not, return FReply::Unhandled() so the game gets the click. CEF will not report that back to Slate on its own, which is why pointer-events looks like it does nothing.

If you and GPT pull it off (whether using JS, modifying the C++, or any other system), you have my praise. And let me tell you, hardly anyone gets that. You’d be the first, and coming from me, that means a lot.

Even if you manage to prevent a specific area of the DOM from consuming the event, the function might still return a reply that captures the mouse. Simply getting an FReply::Unhandled() at some point isn’t enough. You need to understand what WebBrowserWindow->OnMouseButtonDown() actually does, how the final reply is constructed, and how the class hierarchy and inheritance work.

And that’s not all. Modifying the engine code directly makes the solution fragile across updates. Creating a wrapper, on the other hand, means navigating the inheritance hierarchy and its implementation details yourself—with no colleague around to explain, “We did it this way for a reason.”

GPT is bold. But not with me.

In all likelihood, this would require the designers themselves to restructure things and add it to their roadmap. But hey…who the hell am I at EPIC?

So, GPT couldn’t handle the problem? That’s a shame.
Try using Claude.

By the way, you’re pretty good at farming “votes,” aren’t you? You went from a few votes to 20 response points in, what two days?

Congratulations. You should thank GPT.

But please, try doing some research yourself.

This topic is intended for people working on the UE5 backend not for some random person using GPT.

I’ve seen that you’ve mastered every possible architecture (whether it’s GAS, animations, etc.) and you even know Chinese! You should definitely submit your CV to Epic.
I’m envious but are you using Claude, Gemini, or something else?

In all your comments, I only see well-formatted text; I don’t even see an example or a reproducible image. I envy you.

Although the question concerns the Unreal backend, does anyone happen to know anything about this?