HyTeKGames · Web browser for Unity

Ultimate Web View

Put real web pages in your game: on UI, on 3D surfaces, in UI Toolkit. Players click and type in them, and page JavaScript talks to your C# code. One package for Windows, Linux, Android, iOS and WebGL.

Version 1.1.0 Windows · Linux · Android · iOS · WebGL Unity 2020.3 LTS to Unity 7 alpha Built-in · URP · HDRP

1Overview

Ultimate Web View puts web pages into a Unity project. On Windows and Linux it ships its own browser engine (Chromium 156) and draws pages into a texture, so a page can sit on any mesh, in a uGUI RawImage or in a UI Toolkit element. On Android and iOS it uses the web view of the device, as a texture or as a native view over the game. In WebGL builds the page is an iframe placed over the canvas. The same C# API drives all of them. This documentation is both the manual and the scripting reference.

Key features

Pages on any surface

Three display options wrap the same browser: WebViewScreen for meshes in the scene, WebViewImage for uGUI and WebViewElement for UI Toolkit. Or take WebView.Texture and put it wherever you want.

Real input

Mouse, touch, wheel, drag and hover reach the page. A pointer component handles mouse, crosshair, VR controller and gamepad aiming at 3D screens. The physical keyboard types into the focused page with the legacy Input Manager or the Input System.

On-screen keyboard

A keyboard built with UI Toolkit, with QWERTY, AZERTY and QWERTZ layouts, accents, a symbols page and a numeric pad. It docks to the bottom of the screen or lives as a panel in the 3D scene, and shows itself when a text field takes focus.

C# and JavaScript talk

Pages call uwv.postMessage() and your script receives the message. Your script calls PostMessage, ExecuteJavaScript or EvaluateJavaScript and gets values back as JSON.

Sound through Unity audio

On Windows and Linux the sound of a page plays through an AudioSource: 3D position, volume, mixer groups and effects work as for any other sound.

HTML as game UI

Pages with a transparent background show the scene behind them. Load HTML from a string or from StreamingAssets and use it as a HUD or a menu.

Works in the Editor

Web views run in play mode and in edit mode. A Browser window is included, and WebViewElement works in your own editor windows. Entering play mode without a domain reload is supported.

One package, five platforms

Windows, Linux, Android, iOS and WebGL from one code base, with full C# source. Mono and IL2CPP. No setup step and no dependency on other packages.

Stated limits

Every platform has a chapter that lists what its engine can't do. Read section 7 before you plan a feature around video, sound or 3D screens on mobile and WebGL.

How it works

Everything is built on one class, WebView. It owns a browser instance, exposes its page as a Texture, and has methods for navigation, pointer and keyboard input and JavaScript. The components and the UI Toolkit element are thin wrappers that create a WebView, show its texture and feed it input.

You wantUseSection
A page in a uGUI canvasWebViewImage next to a RawImage4
A page on a monitor, a wall or a tablet in the sceneWebViewScreen on the mesh, WebViewPointer on the camera or controller4
A page in a UI Toolkit layout or an editor windowWebViewElement4
Full control from codenew WebView(width, height, url)4
Typing without a physical keyboardWebViewKeyboard4
3D sound from a pageWebViewAudio next to an AudioSource4

Two conventions apply everywhere. Points are normalised: (0, 0) is the top-left corner of the page and (1, 1) the bottom-right. Everything runs on the main thread: call the API from the main thread, and expect every event there.

Platforms at a glance

PlatformEnginePage as textureMain limit
Windows x64Chromium 156, shipped with the buildYesH.264, AAC and HEVC play only with the codec setting, and their patent licences are up to you. Adds about 335 MB to the build.
Linux x64Chromium 156, shipped with the buildYesSame as Windows. Adds about 305 MB to the build.
Unity EditorSame engine, on Windows and LinuxYesThe macOS Editor uses WebKit, as a preview.
AndroidAndroid System WebViewYes or native overlaySound doesn't go through Unity audio. Touch and left button only.
iOSWKWebViewLimited or native overlayTexture mode runs at roughly 10 to 30 frames per second and can't show video. Use the overlay for video.
WebGLAn iframe in the browser that runs the gameNoAlways on top of the canvas. Sites that forbid embedding don't load.
macOSWKWebViewPreviewmacOS 11 or later. Works like iOS: a texture for mostly still pages, or a native overlay.

The full comparison is in section 7.

2Requirements

UnityUnity 2020.3 LTS or newer: 2021.3, 2022.3, 2023.x, Unity 6.x and the Unity 7 alpha.
Render pipelinesBuilt-in, URP and HDRP. The screen shader and the demo scenes work in all three without conversion.
EditorWindows or Linux, 64-bit Intel or AMD processor. macOS 11 or later as a preview.
Build targetsWindows x64, Linux x64, Android, iOS, WebGL, and macOS as a preview. 32-bit Windows and other platforms compile, with blank web views.
Scripting backendsMono and IL2CPP.
InputThe legacy Input Manager, the Input System package, or both. When both are active the Input System is used.
PackagesNone required. WebViewImage exists when the Unity UI package (com.unity.ugui) is installed. The Input System is picked up when it is installed.
AndroidAndroid 6.0 (API 23) or newer for the full texture mode. API 21 and 22 run a reduced software path. The Android System WebView must be installed and enabled on the device.
iOSiOS 13 or newer. Zoom and pixel density need iOS 14.
Disk spaceAbout 640 MB in the project for the two desktop engines, plus 633 MB for their codec files. See section 9.

Some features depend on the Unity version:

FeatureUnity 2020.3Unity 2021.2 and newer
WebViewElementEditor windows only (Unity 2020.3 has no runtime UI Toolkit)Editor windows and runtime UIDocument
On-screen keyboard, Overlay modeDrawn with IMGUI, same keys and layoutsUI Toolkit
On-screen keyboard, World modeNot availableAvailable
KeyboardElementEditor windows onlyEditor windows and runtime UI

If your scripts live in their own assembly definition, add a reference to HyTeKGames.UltimateWebView. All types are in the namespace HyTeKGames.UltimateWebView.

3Installation and first steps

Import the package and you're done: there is no setup wizard, no scripting define to add and no package to install. Nothing opens on import. Start from the Welcome window when you want a guided first step.

Importing the package

Import Ultimate Web View from the Package Manager (My Assets). Everything goes to Assets/HyTeKGames/UltimateWebView. You can move that folder: the package finds its own files by name.

FolderContentIn builds
RuntimeThe C# API, the components, the keyboard and the platform plugins (Java for Android, Objective-C++ for iOS, a .jslib for WebGL).Yes
EditorMenus, the Welcome and Browser windows, the settings page and the build steps.No
EngineThe browser engine for Windows and Linux: Chromium files and the helper program UltimateWebViewHost.uwv in x86_64, and in Codecs the files that replace them when H.264, AAC and HEVC is on.Copied into Windows and Linux builds only
DemoExample scenes, scripts and pages. Safe to delete.Only if you add the scenes to the build
DocumentationThis file.No
Licenses, Third-Party Notices.txtLicences of the browser engine. See section 12.You add them to desktop builds

The first import takes a while because the engine files are large. The first time a web view starts in the Editor, the package copies the engine to Library/UltimateWebView and shows a progress bar: Preparing the browser engine (once per project).... The Editor runs that copy, so the files in Assets are never locked and you can update or delete the package while the Editor is open.

About UltimateWebViewHost.uwv

The browser engine runs in its own process, outside Unity. UltimateWebViewHost.uwv is that program: a 64-bit executable for Windows and one for Linux, stored under a neutral file extension because Asset Store packages can't contain .exe files. The copies made for the Editor and for your builds get their real name (UltimateWebViewHost.exe on Windows, UltimateWebViewHost on Linux). It starts with the first web view, never opens a window of its own (except DevTools when you ask for them) and stops with Unity.

Menu entryWhat it does
Tools > HyTeKGames > Ultimate Web View
WelcomeOpens the start page: three steps to a first web view, shortcuts to the other windows and a platform summary.
BrowserOpens a web browser in an editor window. See below.
SettingsOpens Project Settings > Ultimate Web View. See section 6.
DocumentationOpens this file in your system browser.
GameObject > Ultimate Web View
Web View ScreenCreates a 1.6 x 0.9 quad with a MeshCollider and a WebViewScreen, at the pivot of the Scene view or under the selected object.
Web View Screen (3D Sound)The same, plus an AudioSource set to full 3D and a WebViewAudio.
Web View ImageCreates a RawImage with a WebViewImage that fills its canvas with a 40 pixel margin. A canvas and an EventSystem are created when the scene has none. Needs the Unity UI package.
Web View PointerAdds a WebViewPointer to the camera tagged MainCamera and selects it.
On-Screen KeyboardCreates an object with a WebViewKeyboard.

The components are also in Add Component > Ultimate Web View.

Your first web view

  1. Add a screen Choose GameObject > Ultimate Web View > Web View Screen, or click Add a Web View Screen in the Welcome window. A quad appears in front of the Scene view camera.
  2. Set the URL Select the new object. In its Web View Screen component, open Options and type an address into Url, for example https://example.com.
  3. Add a pointer Choose GameObject > Ultimate Web View > Web View Pointer. Your main camera gets the component that turns the mouse into clicks on the screen.
  4. Press Play The page loads and shows on the quad. Click links, scroll with the wheel, click a text field and type.
Tip

Leave Url empty to get the built-in start page. It tells you the web view works before you point it at your own content.

The Browser window

Tools > HyTeKGames > Ultimate Web View > Browser opens a small browser that runs in edit mode and in play mode. Use it to check that a site works in the engine before you build a scene around it, or to keep a reference page next to the Scene view.

  • The toolbar has Back, Forward, Reload (it becomes Stop while loading) and an address field. Press Enter to load what you typed: an address is loaded as it is, anything else is searched for. Esc puts the current address back.
  • The menu button on the right offers Developer Tools, Zoom In, Zoom Out, Reset Zoom, Copy Address, Open in System Browser and Home.
  • JavaScript alerts and confirmations show as Editor dialogs. The window doesn't save downloads.

The window is an ordinary EditorWindow with a WebViewElement in it. Its source, Editor/Browser/BrowserWindow.cs, is a good model for your own editor tools.

Demo scenes

The Demo folder holds four scenes. They work in the Built-in pipeline, URP and HDRP without conversion, and with either input backend. The pages they show are HTML text assets in Demo/Pages, so the demos also run without an internet connection.

SceneShows
01 BrowserA browser made with uGUI: WebViewImage, an address bar, back, forward and reload buttons, and the on-screen keyboard.
02 World ScreenA room to walk around in, with a computer whose monitor opens Google and a TV that opens YouTube. Both are WebViewScreens used through a WebViewPointer on the camera, with 3D sound through WebViewAudio; the on-screen keyboard opens when you click a text field. Hold the right mouse button to look and move with WASD; on a phone, use the move pad and drag to look. Change the two addresses in Options > Url of the screens.
03 HTML HUDA transparent page as the HUD of a small scene. The page sends commands to C#, and C# sends the state of the scene back.
04 UI ToolkitA WebViewElement inside a UI Toolkit layout, between ordinary controls. Needs Unity 2021.2 or newer.

The Welcome window has a Demo scenes tile that shows the folder in the Project window. You can delete the Demo folder at any time: nothing else depends on it.

4Quick start recipes

Each recipe is self-contained. The C# samples assume using HyTeKGames.UltimateWebView; and using UnityEngine; at the top of the file. What a recipe describes is the behaviour on Windows and Linux; where another platform differs, section 7 says how.

Web page in a uGUI canvas

WebViewImage shows a page in a RawImage. Pointer input comes from the EventSystem, so it works with every input module and ray caster: screen-space canvases, world-space canvases and XR ray interactors.

  1. Choose GameObject > Ultimate Web View > Web View Image. If the scene has no canvas or EventSystem, they are created.
  2. Set Options > Url on the Web View Image component and size the RectTransform as you like.
  3. Press Play.

With Match Rect Size on (the default), the texture has the size of the image on screen, so text is as sharp as the rest of your UI and the page reflows when the rect changes. Clicking the image selects it in the EventSystem and gives the page keyboard focus; selecting something else takes focus away.

Drive it from a script through the component. The web view exists from the moment the component is first enabled in play mode:

using HyTeKGames.UltimateWebView;
using UnityEngine;
using UnityEngine.UI;

public sealed class HelpPanel : MonoBehaviour
{
    public WebViewImage page;
    public Text title;

    void OnEnable()
    {
        page.Created += OnCreated;
        if (page.WebView != null) OnCreated(page.WebView);
    }

    void OnDisable()
    {
        page.Created -= OnCreated;
        if (page.WebView != null) page.WebView.TitleChanged -= OnTitleChanged;
    }

    void OnCreated(WebView webView)
    {
        webView.TitleChanged -= OnTitleChanged;
        webView.TitleChanged += OnTitleChanged;
    }

    void OnTitleChanged(string text)
    {
        title.text = text;
    }

    // Hook this to a Button.
    public void ShowHelp()
    {
        page.Url = "https://example.com/help";
    }
}

The component also has three UnityEvents in the Inspector, On Ready, On Page Loaded and On Message, for wiring without code.

Web page on a 3D object

WebViewScreen shows a page on a mesh: a quad, a plane, the screen of a monitor model. WebViewPointer aims at such screens with a physics ray and turns mouse, touch or your own calls into clicks, drags and scrolling.

  1. Choose GameObject > Ultimate Web View > Web View Screen, or add the Web View Screen component to your own mesh. The object needs a collider; adding the component to a mesh without one adds a MeshCollider.
  2. Set Options > Url and Resolution. With Match Aspect on, only the width counts: the height follows the proportions of the mesh, so the page is never stretched.
  3. Choose GameObject > Ultimate Web View > Web View Pointer to put a pointer on the main camera.

The material. If the renderer still has the default material Unity gives new primitives, or no working material at all, the component replaces it at run time with its own unlit shader (HyTeKGames/Ultimate Web View/Screen), which works in the Built-in pipeline, URP and HDRP. If you assigned your own material, it is kept and the page texture is set on it through a MaterialPropertyBlock: on the property named in Texture Property, or on every one of _MainTex, _BaseMap, _BaseColorMap, _UnlitColorMap and _EmissionMap the material has. Use an unlit or emissive material unless you want scene lighting on the page.

The surface. The page lies on the two largest dimensions of the mesh: X and Y for Unity's quad, X and Z for Unity's plane. For clicks, a MeshCollider on a readable mesh uses the UV coordinates of the hit, so curved screens work. Other colliders use the position of the hit inside the mesh bounds.

The pointer. Pick how it aims with Mode:

ModeAimsTypical use
MouseThrough the mouse position, or the first finger on a touch screen. On touch screens a drag scrolls the page.Desktop and mobile games with a visible cursor. Put it on the camera.
Screen CenterThrough the middle of the view.First-person games with a crosshair.
TransformAlong the forward axis of Ray Origin (or of the pointer's own transform).XR controllers and hands. Turn Read Mouse off and call Press, Release and Scroll from your input.
VirtualThrough the middle of the view until a press or Capture locks the pointer to a surface. From then on mouse movement, or Move, slides a cursor over the page.Locked mouse, gamepad stick.

Screens must be on a layer included in the pointer's Layers and within Max Distance. With Cursor on Auto, the system mouse cursor takes the shape the page asks for in Mouse mode, and a small cursor is drawn on the surface in the other modes.

Driving the pointer from an XR controller or a gamepad:

public sealed class ControllerPointer : MonoBehaviour
{
    // Mode: Transform, Read Mouse: off.
    public WebViewPointer pointer;

    public void OnTriggerDown()
    {
        pointer.Press();
    }

    public void OnTriggerUp()
    {
        pointer.Release();
    }

    // stick.y is positive when pushed up; page pixels are positive downwards.
    public void OnStick(Vector2 stick)
    {
        pointer.Scroll(new Vector2(stick.x, -stick.y) * 30f);
    }
}

Building a screen from code:

GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);   // comes with a MeshCollider
quad.transform.localScale = new Vector3(1.6f, 0.9f, 1f);
WebViewScreen screen = quad.AddComponent<WebViewScreen>();
screen.Url = "https://example.com";

Camera.main.gameObject.AddComponent<WebViewPointer>();
Options from code

A component creates its web view the moment it is enabled, and Options are read once at that moment. To change options from code (for example transparent), add the component to an inactive GameObject, set screen.Options, then activate the object.

Web page in UI Toolkit

WebViewElement is a VisualElement. It creates its web view once it is on a panel and has a size, sizes the texture to the element, and feeds it pointer, wheel and keyboard events. It works in runtime UIDocuments (Unity 2021.2 and newer) and in editor windows (every supported version).

In UXML:

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uwv="HyTeKGames.UltimateWebView">
    <ui:Label text="News" />
    <uwv:WebViewElement name="page" url="https://example.com" style="flex-grow: 1;" />
</ui:UXML>
UXML attributeDefaultWhat it does
urlemptyThe address to load. Empty shows the start page.
transparentfalsePages without a background colour show what is behind the element.
pixel-density1Texture pixels per UI point, on top of the panel scale. 1 is as sharp as the rest of the UI.
interactivetrueFalse shows the page but ignores pointer and keyboard.

In C#:

using HyTeKGames.UltimateWebView;
using UnityEngine;
using UnityEngine.UIElements;

[RequireComponent(typeof(UIDocument))]
public sealed class NewsScreen : MonoBehaviour
{
    WebViewElement page;

    void OnEnable()
    {
        VisualElement root = GetComponent<UIDocument>().rootVisualElement;
        page = new WebViewElement();
        page.style.flexGrow = 1f;
        page.Url = "https://example.com";
        page.Created += OnCreated;
        root.Add(page);
    }

    void OnDisable()
    {
        page.Created -= OnCreated;
        page.RemoveFromHierarchy();
    }

    void OnCreated(WebView webView)
    {
        webView.LoadFinished += OnLoaded;
    }

    void OnLoaded(string url)
    {
        Debug.Log("Loaded " + url);
    }
}

Things to know:

  • Give the element a size (flex-grow, or a width and height). Without one no web view is created.
  • The element takes UI Toolkit focus when clicked, and the keys it receives go to the page. Its web view doesn't use the play-mode hardware keyboard forwarder, so it also types in editor windows.
  • Options holds the remaining settings (popups, startup script and so on). Change them before the element is added to a panel. The address, transparency and pixel density come from the element's own properties, not from Options.
  • A web view the element created is disposed about a second after the element leaves its panel, and a new one is created when it comes back. Dispose() does it immediately.
  • To show a web view you created yourself, assign it: page.WebView = myWebView;. The element then never resizes or disposes it.

An editor window takes a few lines:

using HyTeKGames.UltimateWebView;
using UnityEditor;

public sealed class ReferenceWindow : EditorWindow
{
    [MenuItem("Window/Reference Page")]
    static void Open()
    {
        GetWindow<ReferenceWindow>();
    }

    void OnEnable()
    {
        var page = new WebViewElement();
        page.style.flexGrow = 1f;
        page.Url = "https://example.com";
        rootVisualElement.Add(page);
    }
}

Scripting only: the WebView class

WebView is a plain C# class, not a component. Create one, put its Texture on anything, send it input, and dispose it when you're done.

public sealed class ScriptedPage : MonoBehaviour
{
    public Renderer target;

    WebView webView;

    void Start()
    {
        var options = new WebViewOptions();
        options.url = "https://example.com";
        options.frameRate = 30;

        webView = new WebView(1280, 720, options);
        webView.LoadFinished += OnLoaded;
        webView.LoadFailed += OnFailed;
        target.material.mainTexture = webView.Texture;
    }

    void OnLoaded(string url)
    {
        Debug.Log("Loaded " + webView.Title + " from " + url);
    }

    void OnFailed(LoadError error)
    {
        Debug.LogWarning("Could not load " + error.url + ": " + error.description);
    }

    void OnDestroy()
    {
        if (webView != null) webView.Dispose();
    }
}

The texture is always upright and keeps the same object when the web view is resized, so assign it once. Calls made before the engine has created the browser are queued: you don't have to wait for Ready.

Input uses normalised points, (0, 0) top-left:

Vector2 centre = new Vector2(0.5f, 0.5f);

webView.Click(centre);                              // move, press, release
webView.Scroll(centre, new Vector2(0f, 300f));      // 300 page pixels down
webView.TypeText("unity web view");
webView.SendKey(WebKey.Enter);
webView.SendKey(WebKey.A, KeyModifiers.Control);    // select all

// Or the single steps, for drags and hover:
webView.PointerMove(new Vector2(0.2f, 0.4f));
webView.PointerDown(new Vector2(0.2f, 0.4f));
webView.PointerMove(new Vector2(0.6f, 0.4f));
webView.PointerUp(new Vector2(0.6f, 0.4f));

If you prefer await, two methods return tasks that complete on the main thread:

async void Start()
{
    var webView = new WebView(1024, 768, "https://example.com");
    bool loaded = await webView.WaitForLoadAsync();
    if (loaded)
    {
        string json = await webView.EvaluateJavaScriptAsync("document.title");
        Debug.Log(json);   // "Example Domain", with the quotes: results are JSON
    }
    webView.Dispose();
}
Good to know 
LifetimeA web view lives until you call Dispose(). In the Editor, web views created in play mode are disposed when play mode ends. Web views created in edit mode stay until the next script reload.
SizeWidth and height are texture pixels, clamped to 16 and to the smaller of 8192 and the graphics device limit. Resize keeps the current image until the page has been painted at the new size, then raises TextureResized.
PausingSet Rendering = false while nobody can see the page. The engine stops painting and the texture keeps its last image.
Start-up timeThe engine starts with the first web view, which takes about a second on Windows and Linux. Call WebView.Prewarm() earlier, for example in a loading screen, to move that cost.
Unsupported platformsCheck WebView.IsSupported. Where it is false you can still create web views; they stay blank and a page load reports LoadFailed.

C# and JavaScript

Every page gets a small object, window.uwv, before its own scripts run. It carries messages in both directions. Messages are strings; send JSON when you need structure.

In the page:

// Page to Unity. Objects are sent as JSON, strings as they are.
uwv.postMessage({ type: 'buy', item: 'sword' });

// Unity to page.
uwv.addEventListener('message', function (e) {
    var state = JSON.parse(e.data);
    document.getElementById('gold').textContent = state.gold;
});

uwv.onmessage = function (e) { ... } and uwv.removeEventListener('message', listener) work too. On the desktop engine window.uwv exists before the first script of the page. If your page must also run where the bridge arrives a moment later, wait for it:

if (window.uwv) start();
else window.addEventListener('uwvready', start);

In Unity:

[System.Serializable]
public sealed class ShopCommand
{
    public string type;
    public string item;
}

void Listen(WebView webView)
{
    webView.MessageReceived += OnMessage;
}

void OnMessage(string json)
{
    ShopCommand command = JsonUtility.FromJson<ShopCommand>(json);
    if (command.type == "buy") Debug.Log("The player buys " + command.item);
}

void SendGold(WebView webView, int gold)
{
    webView.PostMessage("{\"gold\":" + gold + "}");
}

With the components, On Message in the Inspector and component.PostMessage(...) do the same without touching WebView.

Running JavaScript. ExecuteJavaScript runs a script and forgets it. EvaluateJavaScript hands you the value of the last expression as JSON: 42, "text", {"a":1} or null.

webView.ExecuteJavaScript("document.body.style.zoom = '1.2'");

webView.EvaluateJavaScript("document.querySelectorAll('a').length", OnCounted, OnScriptError);

void OnCounted(string json)
{
    Debug.Log("The page has " + int.Parse(json) + " links.");
}

void OnScriptError(string message)
{
    Debug.LogWarning("The script failed: " + message);
}

EvaluateJavaScriptAsync is the awaitable form; it throws a WebViewException when the script throws.

Startup script. WebViewOptions.startupScript (or the StartupScript property, from the next page load on) is JavaScript that runs in every page of the web view before the page's own scripts. Use it to define globals or to hook functions:

var options = new WebViewOptions();
options.url = "https://example.com";
options.startupScript = "window.gameVersion = '1.4.2';";
var webView = new WebView(1280, 720, options);
Timing

PostMessage and ExecuteJavaScript act on the page that is loaded at that moment. A message sent while the page is still loading is lost. Wait for LoadFinished (or On Page Loaded), or let the page ask for its state with a first uwv.postMessage('ready').

In WebGL builds all of this works for pages of the same origin as the game. Pages of other origins need a different handshake: see WebGL.

HTML strings and local files

LoadHtml shows a page from a string, for example from a TextAsset:

public TextAsset page;

void Show(WebView webView)
{
    webView.LoadHtml(page.text);

    // With a base address: relative links resolve against it, and it decides the storage origin.
    webView.LoadHtml(page.text, "https://game.example/ui/");
}

Without a base address the page gets https://app.localhost/, so it has a real origin: local storage and cookies work, and fetch behaves as on a normal site. Nothing is requested from that address. Chromium treats such a page as a public site, and public sites normally need a permission to call servers on the local network. On Windows and Linux the engine switches those local network access checks off, so the page can reach a server on the same machine (http://localhost:8080). If a page must talk to a local server on Android, iOS or WebGL too, pass the address of that server as the base address: the page then belongs to its origin.

For pages made of several files (scripts, style sheets, images), put them in StreamingAssets and load the entry file by address:

webView.LoadUrl("streaming-assets://ui/index.html");

// The same, as an ordinary address you can also hand to other code:
string address = WebView.StreamingAssetsUrl("ui/index.html");

The streaming-assets:// scheme works on every platform and in Options > Url too. Such a page loads its scripts, style sheets, images and media from neighbouring files as it is. Reading other local files with fetch, XHR or ES modules needs the setting Local file access, which is off by default.

How LoadUrl reads what you give it:

You passIt loads
example.com/pagehttps://example.com/page. https:// is added when the scheme is missing.
localhost:8080, 127.0.0.1, 192.168.1.20, 10.0.0.5The same with http:// in front.
C:\Pages\index.html, /home/me/index.htmlThe file, as a file:// address.
streaming-assets://ui/index.htmlThe file from StreamingAssets, wherever the platform keeps it.
An empty stringabout:blank on a WebView. The components show the start page instead.

Cookies and stored data

All web views share one browser profile: cookies, local storage, IndexedDB and the HTTP cache. WebViewData is the static class that reads and clears it.

void SignIn(string token)
{
    var cookie = new WebCookie();
    cookie.name = "session";
    cookie.value = token;
    cookie.domain = "example.com";
    cookie.path = "/";
    cookie.secure = true;
    cookie.httpOnly = true;
    cookie.expires = System.DateTimeOffset.UtcNow.AddDays(30).ToUnixTimeSeconds();   // 0 = session cookie
    WebViewData.SetCookie("https://example.com", cookie);
}

void ListCookies()
{
    WebViewData.GetCookies("https://example.com", OnCookies);
}

void OnCookies(WebCookie[] cookies)
{
    foreach (WebCookie c in cookies) Debug.Log(c.name + " = " + c.value);
}

void SignOut()
{
    WebViewData.DeleteCookies("https://example.com", "session");   // leave the name out to delete all of them
}
CallEffect
WebViewData.ClearCookies()Deletes every cookie.
WebViewData.ClearCache()Empties the HTTP cache.
WebViewData.ClearAll()Deletes everything pages have stored: cookies, cache, local storage, IndexedDB, service workers. On Windows and Linux the engine restarts for this, so open pages load again.

Where the profile lives on Windows and Linux:

In the EditorLibrary/UltimateWebView/Profile in the project. Project Settings > Ultimate Web View has Clear cookies and cache and Open profile folder buttons.
In a buildUltimateWebView inside Application.persistentDataPath.
Persistent storage offA temporary folder that is deleted when the engine stops. Nothing survives the session.
Second instanceWhen another instance of the same game or Editor project already uses the profile, the new instance runs from a temporary profile. Both keep working; the second one starts signed out.

WebViewOptions.incognito keeps the cookies and storage of one web view in memory only, apart from the shared profile. On Android and iOS the cookie calls have limits (see Android), and in WebGL builds WebViewData does nothing because cookies belong to the browser.

Page sound through Unity audio

On Windows and Linux the engine hands the sound of each page to Unity, and it plays through an AudioSource. That makes it part of your mix: volume, mixer groups, effects, pausing with the AudioListener, and 3D position.

  • Nothing to do for plain sound. A web view that starts playing gets an automatic 2D AudioSource.
  • 3D sound. Put an AudioSource and a Web View Audio component on the same object as the WebViewScreen (or use GameObject > Ultimate Web View > Web View Screen (3D Sound)). Set Spatial Blend to 1 and shape the roll-off as for any source. The screen binds to it when it creates its web view.
  • Your own web view. Bind it from code, as below.
void AddSpeaker(GameObject speaker, WebView webView)
{
    AudioSource source = speaker.AddComponent<AudioSource>();
    source.spatialBlend = 1f;
    source.maxDistance = 15f;

    WebViewAudio output = speaker.AddComponent<WebViewAudio>();
    output.Bind(webView);
}

The AudioSource only plays while the page makes sound, so silent pages don't hold a voice. WebView.Muted silences a page, IsPlayingAudio and AudioStateChanged tell you when it makes sound. A web view has one output: binding it to another WebViewAudio releases the previous one.

Turn Options > Unity Audio off to let the engine play through the system output directly, outside Unity's mix. On Android, iOS and WebGL the browser always plays its own sound: WebViewAudio does nothing there, and 3D sound from pages isn't possible.

On-screen keyboard

WebViewKeyboard is a keyboard for players without a physical one: touch screens, VR, kiosks, consoles with a pointer. Choose GameObject > Ultimate Web View > On-Screen Keyboard. With Auto Show on (the default) it appears when a text field of a web view takes focus and goes away when the field loses it. No code is needed.

ModeWhere it showsHow it is pressed
OverlayDocked to the bottom of the screen, above the rest of the UI, sliding in and out. Height is a fraction of the screen height.Mouse and touch, several fingers at once. Clicks on the keyboard don't reach 3D screens or UI behind it and don't take focus from the page.
WorldOn a panel in the scene, at the position and rotation of the component's object. World Size is in metres. Unity 2021.2 or newer.With a WebViewPointer: mouse, crosshair or VR controller. The panel faces the same way as Unity's quad, so point the object's forward axis away from the viewer.

Layouts. QWERTY (English, United States), AZERTY (French) and QWERTZ (German), each with its Shift and AltGr levels and its accent keys: press ^, then e, to type ê. A symbols page is the same for every layout. Number and telephone fields get a numeric pad. With Show Layout Key on, a key switches between the three layouts. Tap Shift for one capital, hold it or tap it twice to lock. Held keys repeat.

public sealed class KeyboardSetup : MonoBehaviour
{
    public WebViewKeyboard keyboard;
    public WebViewScreen screen;

    void Start()
    {
        keyboard.Layout = KeyboardLayoutType.Azerty;
        keyboard.HideOnEnter = true;
        keyboard.Shown += OnShown;
        keyboard.Hidden += OnHidden;

        // Serve one web view only. Leave Target null to serve whichever web view has focus.
        keyboard.Target = screen.WebView;
    }

    void OnShown()
    {
        Debug.Log("Keyboard up");
    }

    void OnHidden()
    {
        Debug.Log("Keyboard down");
    }
}

Show() and Hide() override the automatic behaviour until focus changes again. WebViewKeyboard.IsOpen is true while any on-screen keyboard is visible. The mode is set in the Inspector; it can't be changed from code.

While an On-Screen Keyboard component is enabled, phones and tablets keep their system keyboard closed. The keyboard serves web views that render to a texture; overlay web views (WebGL, native overlay on mobile) use the keyboard of the system or browser.

The keyboard in your own UI. KeyboardElement is the same keyboard as a UI Toolkit control. Put it anywhere in a layout, and use its events to type into your own text fields too:

var keys = new KeyboardElement();
keys.Layout = KeyboardLayoutType.Qwertz;
keys.style.height = 320f;
keys.TextEntered += OnText;         // Action<string>: text typed, accents combined
keys.KeyPressed += OnKey;           // Action<WebKey, KeyModifiers>: Backspace, Enter, Tab, arrows
keys.HideRequested += OnHide;       // the hide key; the element doesn't hide itself
root.Add(keys);

It types into the focused web view, or into Target when you set one, and never takes focus away from anything. In UXML it is <uwv:KeyboardElement layout="Azerty" show-hide-key="false" />, with the attributes layout, numeric-mode, show-layout-key, show-hide-key and light-theme.

Hardware keyboard and input systems

In play mode the physical keyboard types into the web view that has focus. A web view gets focus when it is clicked (PointerDown) or when you call Focus(); Blur() or a click outside takes it away. WebView.Focused is the web view that has it.

  • Both input backends. The forwarder reads the Input System when the package is installed and active, otherwise the legacy Input Manager. You don't choose; it follows Active Input Handling in the Player settings.
  • Your game still gets the keys. Nothing is consumed. Before you act on a key, check WebView.IsEditingText: it is true while the user types into a text field of a page.
  • Layouts. Characters come from the operating system layout, AltGr combinations included. Shortcuts follow the printed letter: on an AZERTY keyboard Ctrl+A selects all.
  • Your own key handling. Set webView.HardwareKeyboard = false and send keys yourself with KeyDown, KeyUp, SendKey and TypeText.
void Update()
{
    // Don't open the inventory while the player types "i" into a search box.
    if (WebView.IsEditingText) return;
    if (Input.GetKeyDown(KeyCode.I)) ToggleInventory();
}

TypeText sends characters found on a keyboard as real key presses, so pages that listen to key events react. Everything else (accents, emoji, other scripts) is inserted directly. The clipboard and undo commands are methods: Copy(), Cut(), Paste(), SelectAll(), Undo(), Redo(), DeleteSelection().

On phones and tablets, tapping a text field of a texture web view opens the system keyboard and types what the user enters into the page. Turn that off with the System keyboard setting, or enable an On-Screen Keyboard component, which takes over.

Popups, dialogs, downloads, permissions and errors

A game has no window manager, no download folder and no permission bar. Each of those browser features becomes an event you can handle, with a safe default when you don't.

The page doesDefaultYour hook
Opens a new window (target="_blank", window.open)The link loads in the same web view.WebViewOptions.popups: OpenInSameView, NotifyOnly (nothing loads, PopupRequested gives you the address) or Block.
Calls alert, confirm or prompt, or asks before leavingAccepted at once. The text of an alert is written to the Console.DialogOpened. With a listener the page waits until you call Accept or Cancel.
Starts a downloadNothing is saved.DownloadRequested tells you the address, the suggested file name and the MIME type. Fetch the file yourself, for example with UnityWebRequest.
Asks for the camera or microphoneDenied.The setting Camera and microphone grants every such request. Other permission prompts (location, notifications) are denied.
Can't be loadedA short error page with the reason is shown in the web view.LoadFailed carries the address, an engine error code and a description. Turn WebViewOptions.errorPage off to show your own UI; the web view then shows an empty page.
Writes to the JavaScript consoleNothing.ConsoleMessage, or the setting Page console to Unity console.
Crashes its processThe page is reloaded.Crashed. See Restart after crash in the settings.
void Wire(WebView webView)
{
    webView.PopupRequested += OnPopup;
    webView.DialogOpened += OnDialog;
    webView.DownloadRequested += OnDownload;
    webView.LoadFailed += OnLoadFailed;
}

// Needs options.popups = PopupMode.NotifyOnly.
void OnPopup(string url)
{
    Application.OpenURL(url);
}

void OnDialog(ScriptDialog dialog)
{
    if (dialog.Type == DialogType.Confirm)
    {
        // Show your own UI here and call Accept or Cancel when the player decides.
        dialog.Cancel();
        return;
    }
    dialog.Accept();
}

void OnDownload(DownloadRequest request)
{
    Debug.Log("The page offers " + request.suggestedFileName + " at " + request.url);
}

void OnLoadFailed(LoadError error)
{
    Debug.LogWarning(error.description + " (" + error.code + ")");
}

Always answer a ScriptDialog you receive: the page is paused until you do. Reload() after a failed load tries the address that failed, not the error page.

A transparent page as HUD

With transparent on, every part of a page that has no background shows what is behind it. That makes HTML and CSS usable for HUDs, menus and overlays.

  1. Create a Web View Image that fills a Screen Space - Overlay canvas.
  2. Turn on Options > Transparent.
  3. Write the page without a background: html, body { background: transparent; margin: 0; }.
  4. Load it from a TextAsset or from StreamingAssets, and exchange messages.
public sealed class Hud : MonoBehaviour
{
    public WebViewImage hud;      // Options > Transparent on, On Message wired to OnHudMessage
    public TextAsset page;

    [System.Serializable]
    sealed class HudState
    {
        public int health;
        public int ammo;
    }

    void Start()
    {
        hud.LoadHtml(page.text);
    }

    public void OnHudMessage(string message)
    {
        if (message == "pause") Time.timeScale = 0f;
        if (message == "resume") Time.timeScale = 1f;
    }

    public void Refresh(int health, int ammo)
    {
        var state = new HudState();
        state.health = health;
        state.ammo = ammo;
        hud.PostMessage(JsonUtility.ToJson(state));
    }
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
  html, body { background: transparent; margin: 0; font: 600 22px system-ui, sans-serif; color: #fff; }
  #bar { position: fixed; left: 24px; bottom: 24px; }
  button { position: fixed; right: 24px; top: 24px; }
</style>
</head>
<body>
  <div id="bar">Health <span id="health">100</span> &middot; Ammo <span id="ammo">0</span></div>
  <button onclick="uwv.postMessage('pause')">Pause</button>
  <script>
    uwv.addEventListener('message', function (e) {
      var state = JSON.parse(e.data);
      document.getElementById('health').textContent = state.health;
      document.getElementById('ammo').textContent = state.ammo;
    });
  </script>
</body>
</html>

Limits to plan for:

  • Clicks don't pass through transparent areas. A full-screen WebViewImage receives every click on it, also where the page is see-through. For a HUD that only displays, turn Interactive off and clear Raycast Target on the RawImage. For a HUD with a few buttons, size the image to the area that holds them, or use two web views.
  • Cost. A full-screen page at a high resolution is a large texture that is uploaded each time the page changes. Keep animations small, lower Frame Rate, or use Resolution Scale below 1. See section 8.
  • Platforms. In WebGL builds the page is always above the canvas, which suits a HUD. On iOS, texture mode is slow for anything animated.

The scene 03 HTML HUD in the Demo folder is a working version of this recipe.

5Components

This section lists every Inspector field. The names are the labels you see in the Inspector. The matching script members are in section 10.

Shared fields and options

Web View Screen and Web View Image share these fields. Both create their web view when they are first enabled in play mode and dispose it when they are destroyed. Disabling the component keeps the web view and its page.

FieldDefaultWhat it does
Options The settings of the web view, listed below. They are read once, when the web view is created.
InteractiveOnLets pointers click, scroll and type into the page. Off shows the page only.
Pause When DisabledOnStops painting and mutes the page while the component is disabled. Turn it off to keep a page running (music, a timer) while its object is hidden.
On Ready UnityEvent. The browser exists.
On Page Loaded UnityEvent with a string. A page finished loading; the argument is its address.
On Message UnityEvent with a string. The page called uwv.postMessage. Objects arrive as JSON.

The fields of Options (the class WebViewOptions):

FieldDefaultWhat it does
UrlemptyThe page loaded at start. The components show the built-in start page when it is empty.
Render ModeTextureTexture draws the page into a texture. Native Overlay makes Android and iOS place the system browser view on top of the game, at the place of the component on screen. Windows and Linux always use a texture, WebGL always uses an overlay.
TransparentOffPages without a background colour are see-through.
Frame Rate60Upper limit of page repaints per second, 1 to 60. The texture is only updated when the page changes, so a still page costs nothing.
Pixel Density1Texture pixels per page pixel, 0.5 to 4. At 2, a 1280 x 720 texture shows a 640 x 360 layout with text twice as sharp.
MutedOffStarts with the sound off.
Unity AudioOnWindows and Linux: plays the sound of the page through an AudioSource. Off lets the engine play through the system output.
IncognitoOffKeeps the cookies and storage of this web view in memory only.
PopupsOpen In Same ViewWhat happens when a page opens a new window: load it in this web view, report it through PopupRequested only, or block it.
Startup ScriptemptyJavaScript that runs in every page of this web view before the page's own scripts.
Error PageOnShows a short message in the page when an address can't be loaded.
Mip MapsOffGenerates mip maps and uses trilinear filtering, which keeps text stable on screens seen from far away or at an angle. Costs CPU time on every repaint.

Web View Screen

Shows a page on a mesh. Add Component > Ultimate Web View > Web View Screen.

FieldDefaultWhat it does
Resolution1280 x 720Texture width and height in pixels.
Match AspectOnTakes the width from Resolution and derives the height from the proportions of the mesh, scale included. The texture follows when you scale the object.
Target RendereremptyThe renderer that shows the page. Empty uses the renderer on this object.
Texture PropertyemptyThe material texture property that receives the page. Empty sets every common one the material has: _MainTex, _BaseMap, _BaseColorMap, _UnlitColorMap, _EmissionMap.
Brightness1Multiplies the page colour, 0 to 4. Only used by the package's own screen shader. Values above 1 make the screen glow with bloom.
Pause When Not VisibleOffStops painting the page while no camera sees the renderer. The Scene view camera counts in the Editor. Sound keeps playing.
  • The object needs a collider for WebViewPointer to hit. A MeshCollider gives exact results on curved or UV-mapped screens, if the mesh has Read/Write enabled.
  • The texture is set on the renderer, so it reaches every material of a multi-material renderer that has the property. Give the screen its own renderer, or name a Texture Property that only the screen material has.
  • With Render Mode on Native Overlay on a phone, the native view covers the rectangle that the screen occupies on the display. It can't be rotated or hidden behind other objects.

Web View Image

Shows a page in a uGUI RawImage and takes input from the EventSystem. Add Component > Ultimate Web View > Web View Image. The component exists when the Unity UI package is installed.

FieldDefaultWhat it does
Match Rect SizeOnSizes the texture to the image as it appears on screen, canvas scaling included. On world-space canvases the size in canvas units is used.
Resolution1280 x 720Texture size in pixels when Match Rect Size is off.
Resolution Scale1Multiplies the texture size. Above 1 is sharper, below 1 is cheaper.
Scroll Speed1Multiplies the distance of one mouse wheel notch (100 page pixels).
Cursor IconsOnShows the cursor the page asks for (a hand over links, an I-beam over text) while the mouse is over the image.
  • The canvas needs a GraphicRaycaster and the scene an EventSystem, as for any interactive uGUI element.
  • The image takes every click inside its rectangle, also where a transparent page shows nothing.
  • On a touch screen, dragging scrolls the page.
  • Rotating or masking the image works: the page is an ordinary texture. In Native Overlay mode (and in WebGL) the page is a rectangle above everything Unity draws.

Web View Pointer

Aims at WebViewScreens and at the world-space keyboard with a physics ray. Add Component > Ultimate Web View > Web View Pointer. One pointer serves every screen in the scene. Use several for several controllers.

FieldDefaultWhat it does
ModeMouseHow the pointer aims: Mouse, Screen Center, Transform or Virtual. See the table in section 4.
Target CameraemptyThe camera of the Mouse, Screen Center and Virtual modes. Empty uses the main camera.
Ray OriginemptyTransform mode: the ray starts here and follows its forward axis. Empty uses the pointer's own transform.
Max Distance20Length of the ray in metres.
LayersDefault raycast layersThe layers the ray hits. A collider on one of these layers in front of a screen blocks the pointer, as a wall would.
Read MouseOnReads buttons and the wheel from the mouse or the first finger. Turn it off to drive the pointer with Press, Release, Scroll and Move.
Scroll Speed1Multiplies the distance of one mouse wheel notch (100 page pixels).
Drag ScrollsOffDragging scrolls the page like on a touch screen instead of selecting text. Touch input always does this.
CursorAutoAuto: the system cursor in Mouse mode when a mouse is present, a cursor drawn on the surface otherwise. None, Hardware and World force one behaviour.
Cursor Size0.02Size of the drawn cursor as a fraction of the view height, so it looks the same at any distance.
Click Outside BlursOnA press that hits no surface takes keyboard focus away from the focused web view.
Ignore When Over UIOnIgnores the pointer while it is over uGUI or over UI that covers the scene, such as the on-screen keyboard.

The pointer also works with your own surfaces: anything that implements IWebViewPointerTarget on a GameObject with a collider receives moves, presses and scrolling.

Web View Audio

Plays the sound of one web view through the AudioSource on the same object. Add Component > Ultimate Web View > Web View Audio. Windows and Linux only.

The component has no fields of its own. Set up the AudioSource as for any sound: Spatial Blend, Volume, Output mixer group, roll-off. Leave AudioClip empty. On the same object as a WebViewScreen or WebViewImage it binds by itself; for other web views call Bind.

On-Screen Keyboard

The keyboard component, WebViewKeyboard. Add Component > Ultimate Web View > On-Screen Keyboard.

FieldDefaultWhat it does
ModeOverlayOverlay docks the keyboard to the bottom of the screen. World shows it on a panel in the scene, at this object's position.
LayoutQwertyQwerty (English, United States), Azerty (French) or Qwertz (German).
Auto ShowOnShows the keyboard when a text field of a web view takes focus and hides it when the field loses focus.
Height0.38Overlay mode: height as a fraction of the screen height, 0.2 to 0.6. It is reduced on screens that are too narrow for it.
Light ThemeOffLight keys instead of dark ones.
Show Layout KeyOnShows a key that switches between QWERTY, AZERTY and QWERTZ.
Hide On EnterOffHides the keyboard when Enter is pressed in a single-line field.
World Size0.9 x 0.32World mode: size of the panel in metres.
Pixels Per Metre1600World mode: texture pixels per metre of the panel. Higher is sharper and costs more memory.
  • The keyboard restyles through USS. Its class names are constants on KeyboardElement (uwv-keyboard, uwv-keyboard__key and so on); add your own style sheet to keyboard.Element.
  • One keyboard is enough for a scene. In World mode, place the object where the player can reach it and give the pointer a line of sight to it.

6Settings

Project-wide settings are in Project Settings > Ultimate Web View (or Tools > HyTeKGames > Ultimate Web View > Settings). They are stored in Assets/Resources/UltimateWebViewSettings.asset, which is created the first time you change a value. Without the asset every setting keeps its default.

When changes apply

Settings are read when the browser engine starts. In the Editor that is after the next script reload; in a build, at the first web view.

The Status card at the top shows whether the Windows and Linux engines are in the project, whether the engine runs in the Editor, and what the active build target supports. Its buttons Clear cookies and cache and Open profile folder act on the Editor profile.

SettingDefaultWhat it doesApplies to
Browser engine
Hardware accelerationOffUses the GPU for page compositing, WebGL and video decoding. Off, pages are rasterised on the CPU, which is the cheapest path for ordinary pages because every frame goes to system memory anyway. Turn it on for pages with heavy WebGL or large videos.Windows, Linux
SandboxOnRuns the processes that handle page content inside the Chromium sandbox: they can't read files, start programs or reach devices. Turn it off only for a page that needs something the sandbox forbids. Linux always runs without it, because the Chromium sandbox there depends on a root-owned helper or on user namespaces that many distributions switch off.Windows
Persistent storageOnKeeps cookies, local storage and the HTTP cache between sessions. On Android, off clears them for the whole app when the first web view is created.All except WebGL
AutoplayOnLets videos and sounds start without a click.All
Camera and microphoneOffGrants camera and microphone requests of pages. Off, they are denied. On mobile the app also needs the system permission: see Android and iOS.All
Local file accessOffLets local pages (StreamingAssets, file://) read other local files with fetch, XHR and modules, and lets Android and iOS load pages from anywhere on the device. Off, pages in StreamingAssets still load with their scripts, styles and images, and pages from the web can never read local files.Windows, Linux, Android, iOS, macOS
User agentemptyReplaces the User-Agent header. Empty keeps the engine default.Windows, Linux, Android, iOS
Media
H.264, AAC and HEVCOffRuns the engine build that also plays H.264 and AAC: MP4 files, HLS streams (.m3u8), Twitch and most live video. HEVC (H.265) plays as well when Hardware acceleration is on and the GPU decodes it. The Editor and Windows and Linux builds use the files of Engine/<Platform>/Codecs instead of their standard namesakes. These codecs are covered by patents: you are responsible for any licence your product needs, see the note below. While it is off, the inspector of Web View Screen and Web View Image warns when the address is a site known to need these codecs, such as Twitch, or an MP4 file or HLS stream.Windows, Linux
DRM (Widevine)OffLets pages play media protected with Widevine. Windows and Linux: when the engine starts it downloads Google's Widevine module through Chromium's component updater and keeps it in the profile; on Linux the module works from the next engine start on. Android: grants the page's request for protected media, and the device's Widevine does the rest. On Windows and Linux protected audio plays, but protected video stays black in the texture (its sound plays): Chromium keeps decrypted frames out of off-screen rendering. Most protected media also needs H.264, AAC and HEVC. See Windows.Windows, Linux, Android
Browsing
Home pagehttps://www.google.com/The page the Browser window opens first and its Home button returns to. The demo browser takes its search address from here as well.Editor, demo
Search addressGoogleWhere words typed into an address bar are sent. {0} stands for the search text. UltimateWebViewSettings.SearchAddress(text) gives you the finished address for your own address bar.Editor, demo, your code
Android and iOS
System keyboardOnOpens the system keyboard when a text field of a texture web view is tapped. It stays closed while an On-Screen Keyboard component is enabled.Android, iOS
Development
Remote debugging port0Port for Chrome DevTools: open chrome://inspect in a Chromium browser on the same machine and add localhost:port. 0 turns it off. On Android any value other than 0 enables WebView debugging in release builds too.Windows, Linux, Android
Extra engine argumentsnoneChromium command line switches, one per line, with or without the leading dashes: disable-web-security, lang=fr, proxy-server=host:3128. Your switches win over the package defaults.Windows, Linux
Ignore certificate errorsOffLoads pages even when their HTTPS certificate is invalid. For development servers only. The settings page shows a warning while it is on.Windows, Linux; Android and iOS in development builds
Engine log levelErrorsWhich engine messages reach the Unity Console: Off, Errors, Warnings or Everything. Everything also writes the full log of the helper process to Logs/UltimateWebViewHost.log in the project, or to UltimateWebViewHost.log in Application.persistentDataPath in a build.Windows, Linux
Page console to Unity consoleOffWrites the JavaScript console of every page to the Unity Console.All
Reliability
Restart after crashOnStarts the engine again and reloads the open pages if it ever stops unexpectedly, up to three times a minute. Every restart logs a warning.Windows, Linux

Select the asset shows the settings asset in the Project window. Reset to defaults puts every value back. From code, UltimateWebViewSettings.Instance gives you the same object; change it before the first web view is created (or before WebView.Prewarm()) for the change to count.

Patented codecs

H.264, AAC and HEVC are covered by patents, licensed by pools such as Via Licensing Alliance and Access Advance. The licences in section 12 are copyright licences and grant no patent rights. With H.264, AAC and HEVC off, which is the default, your builds contain only the standard Chromium engine. With it on, find out which licences your product needs before you ship. Android, iOS, macOS and WebGL always use the decoders of the system or the browser.

Before you ship

Set Remote debugging port back to 0 and turn Ignore certificate errors off. An open debugging port lets any program on the machine control the pages of your game.

7Platforms

The C# API is the same everywhere, but four different engines sit behind it, and they can't all do the same things. This section says what each one does and where it stops. If a feature matters to your game, check its row before you build on it.

Feature comparison

FeatureWindows, LinuxAndroidiOSWebGL
Display
EngineChromium 156, in the buildAndroid System WebView of the deviceWKWebView of the deviceiframe in the player's browser
Page as a texture (3D, rotation, masks, things drawn above it)YesYes API 23 and newer. Reduced on 21 and 22.Limited about 10 to 30 fpsNo
Native overlayNo not neededYesYesAlways
Largest texture81924096Device limitNot applicable
Transparent pagesYesYesYesYes
Frame rate limit1 to 601 to 601 to 60 asked, about 10 to 30 reached in texture modeIgnored: the browser paints
Pixel densityYesNo follows the screenYes iOS 14Follows the browser
ZoomYesYes through CSS zoomYes iOS 14Yes
Media
Video: WebM, VP8, VP9, AV1, Opus, VorbisYesWhat the device decodesOverlay only. What the device decodes.What the browser decodes
Video: MP4 and HLS with H.264 and AACSetting H.264, AAC and HEVCYesOverlay onlyYes
Video: HEVC (H.265)Setting H.264, AAC and HEVC with Hardware acceleration and a GPU that decodes itWhat the device decodesOverlay only. What the device decodes.What the browser decodes
DRM video (Widevine, FairPlay)Sound only DRM (Widevine): protected audio plays, protected video stays black in the textureSetting DRM (Widevine), the device's WidevineNo in a textureBrowser dependent
WebGL content in pagesYesYes API 23 and newerOverlay may be missing in a textureYes
Sound through Unity audio, 3D soundYesNoNoNo
MuteYesYesBest effortSame origin only
Fullscreen videoInside the web viewNoOverlay, iOS 15.4Yes
Input
PointerThree buttons, hover, wheel, drag, double clickTouch or left button, wheelSimulated with JavaScript in texture modeThe browser's own pointer
Hardware keyboardYesYesYes no IME compositionThe browser's own
On-screen keyboard componentYesYes texture modeYes texture modeNo
System keyboard for text fieldsNot applicableYesYesThe browser's own
Cursor shape (CursorChanged)YesNoYesNo
Scripting
JavaScript and messagesYesYesYesSame origin other origins by handshake
LoadHtmlYesYesYesYes
Extra request headersPage requestMain request onlyFirst main request onlyNo
Cookies (WebViewData)YesLimitedYesNo
Incognito web viewsYesNoYesNo
Popup, dialog and download eventsYesYesYesNo
AudioStateChanged, IsPlayingAudioYesNoNoNo
Developer toolsDevTools window, remote portChrome remote debugging, development buildsSafari Web Inspector, development builds, iOS 16.4The browser's own
Shipping
Added to the buildAbout 335 MB (Windows), 305 MB (Linux)A few small Java classesOne source fileOne script

Windows

How it works. The package ships Chromium 156 through the Chromium Embedded Framework (CEF). The engine runs in a helper process, UltimateWebViewHost.exe, started by the first web view. Each page is rendered off-screen. Finished frames reach Unity through shared memory and are uploaded into a Texture2D; input, navigation and JavaScript travel over a local connection between the two processes. Page sound is captured by the engine and played by Unity. A crash inside a page or the engine can't take your game down, and the helper stops when the game stops, however it ends.

Requirements64-bit Windows 10 or newer, x64 processor. Direct3D 11, Direct3D 12, Vulkan and OpenGL all work, because the texture is filled from memory. Mono and IL2CPP.
In the buildThe folder <Game>_Data/UltimateWebView, about 335 MB.
ProfileUltimateWebView in Application.persistentDataPath.
Developer toolswebView.OpenDevTools() opens a DevTools window. The Remote debugging port setting lets an external Chromium browser attach.

Limits.

  • H.264, AAC and HEVC only with the codec setting. The standard engine is the stock Chromium build: WebM with VP8, VP9 or AV1 video and Opus or Vorbis sound plays, as do Ogg, WAV, FLAC and MP3 audio. MP4 files with H.264 or AAC, HLS streams and sites that only offer such streams, Twitch among them, don't. Turn on H.264, AAC and HEVC to use the engine build that plays them; HEVC also needs Hardware acceleration and a GPU that decodes it. The patent licences these codecs may need are your responsibility. With the setting off, encode your own videos as WebM.
  • DRM plays protected audio, not protected video. With DRM (Widevine) on, the engine downloads Google's Widevine module from Google's update servers when it starts. Protected audio then plays. Protected video plays its sound, but its picture stays black: Chromium keeps decrypted frames out of off-screen rendering, and that is how the engine fills the texture, with or without hardware acceleration. On Windows, Netflix, Disney+, Prime Video and similar services also demand a browser signed through Widevine's certification (VMP), which no custom Chromium build has, and refuse to play at all.
  • 60 frames per second at most, and frames cross process and CPU memory on their way to the GPU. A page is a browser, not a video player tuned for 4K.
  • Size. About 335 MB on disk, most of it one library. See section 9.
  • The helper is not code-signed. Antivirus software and Windows SmartScreen judge an unsigned program by reputation. If you sign your game, sign UltimateWebViewHost.exe in your build as well.
  • The Chromium sandbox is on. The processes that run page content are locked down as in a desktop browser. The launcher UltimateWebViewHost.exe is the bootstrap program of the Chromium Embedded Framework and loads UltimateWebViewHost.dll; keep the two together. The setting Sandbox turns it off.
  • No windows from pages. Popups, file choosers, print dialogs and context menus never open. Popups follow WebViewOptions.popups; a page that asks for a file gets none.
  • No 32-bit and no ARM64 builds. Web views stay blank there and the build logs a warning.

Linux

How it works. The same engine and the same architecture as on Windows: Chromium 156, a helper process (UltimateWebViewHost), shared memory for frames and sound.

Requirements64-bit x86 Linux with glibc, and the system libraries any Chromium-based browser needs (NSS, ATK, CUPS, GBM and the like; a desktop installation has them). X11 and Wayland sessions both work.
Without a displayThe engine renders without a display server, so web views also work in headless builds and on build machines. OpenDevTools() needs a display; use the remote debugging port instead.
In the buildThe folder <Game>_Data/UltimateWebView, about 305 MB.
ProfileUltimateWebView in Application.persistentDataPath.

Limits. Everything listed for Windows applies, apart from code signing. In addition:

  • The helper needs its executable permission. The package sets it each time it starts the engine, which fails when the game is installed in a folder it can't write to. Package Linux builds in a format that keeps permissions (.tar.gz).
  • Chromium's local network access check stays on (only the Windows engine switches it off). A page loaded with LoadHtml and the default base address can be refused when it calls a server on the local network. Pass the address of that server as the base address. See HTML strings.
  • The Chromium sandbox is off on Linux: page processes run with the rights of the game. Show content you trust, or content from the open web that you would also open in a browser at your own risk.
  • With DRM (Widevine) on, a Widevine module the engine has just downloaded works from the next engine start on: Linux loads it while the engine starts. With the setting off, a module downloaded earlier stays unused.
  • HEVC has no software decoder in Chromium. On Linux it needs hardware decoding through VA-API, which depends on the GPU and its driver, and it hasn't been tested there. H.264 and AAC play without it.
  • ARM64 Linux is not supported.

Unity Editor

How it works. The Windows and Linux Editors use the desktop engine, whatever the active build target is. You see Chromium in the Editor even when the target is Android, iOS or WebGL; the device will use its own engine, so test there before you trust a layout or a video.

  • Edit mode and play mode. WebView, WebViewElement and the Browser window work without entering play mode. The components create their web view in play mode only.
  • Engine copy. The Editor runs the engine from Library/UltimateWebView, copied once per project and again when the package is updated.
  • Script reloads. The engine stops at every script reload and starts again on demand. Components restore their page after a reload in play mode. Web views created in play mode are disposed when play mode ends. The engine itself stays warm between play sessions, so the second Play is fast.
  • Enter Play Mode Options. Disabled domain and scene reload are supported.
  • Sound. Page sound goes through Unity audio in play mode. Edit-mode web views play through the system output.
  • Profile. Library/UltimateWebView/Profile, separate for every project and never part of a build.

Limits. The macOS Editor uses WebKit instead of Chromium, as a preview: see macOS. Linux and Windows Editors on ARM processors are not supported.

Android

How it works. The package uses the Android System WebView, the Chromium-based component every Android device has and updates through the Play Store. Two modes exist, chosen with Options > Render Mode:

  • Texture (the default). The WebView is kept off-screen and its drawing is captured through a hardware canvas into a Unity texture. Pages show on 3D objects and in UI like on desktop, with video and WebGL.
  • Native Overlay. The WebView is a native view on top of the Unity view, placed over the rectangle of your component. It is the device's browser view as it is: its own scrolling, text selection, pickers and keyboard.

In texture mode the size of the page comes from the texture, not from the phone: a page is as many CSS pixels wide as the texture divided by Pixel Density, whatever the density of the display. A 1280 pixel wide screen with Pixel Density 1 gets the desktop layout of a site, as on Windows; raise the density to 2 or 3 for larger text and the phone layout.

RequirementsAndroid 6.0 (API 23) or newer for texture capture. On API 21 and 22 a software path draws pages without video and without WebGL. The Android System WebView must be installed and enabled.
Graphics APIsOpenGL ES 3 and Vulkan. Mono and IL2CPP.
ManifestChanged for you at build time: see below.
Developer toolsIn development builds, connect the device by USB and open chrome://inspect in Chrome on your computer.

What the build step does. When you build for Android, the package edits the generated manifest (not your project files):

  • adds the INTERNET permission;
  • sets hardwareAccelerated="true" on the application and its activities, which the texture capture needs;
  • sets usesCleartextTraffic="true" so http:// pages load, unless your manifest already sets that attribute or has a networkSecurityConfig;
  • with Camera and microphone on, adds CAMERA, RECORD_AUDIO and MODIFY_AUDIO_SETTINGS;
  • adds keep rules so code shrinking doesn't remove the package's Java classes.

The manifest entries don't grant the camera or the microphone. Android asks the user at run time, and your app has to make that request before the page does:

// Android only. Wrap in #if UNITY_ANDROID in a multi-platform project.
using UnityEngine.Android;

if (!Permission.HasUserAuthorizedPermission(Permission.Camera))
    Permission.RequestUserPermission(Permission.Camera);
if (!Permission.HasUserAuthorizedPermission(Permission.Microphone))
    Permission.RequestUserPermission(Permission.Microphone);

Limits in both modes.

  • Sound plays through Android's own output, not through Unity audio: no WebViewAudio, no 3D sound, no mixer. Muted works. IsPlayingAudio and AudioStateChanged don't report.
  • One cookie store per app. incognito is ignored. With Persistent storage off, cookies, storage and cache are cleared when the first web view is created, and that affects every WebView in the app, those of advertising or login SDKs included.
  • Cookies API. GetCookies returns names and values only (no domain, path, expiry or flags). DeleteCookies removes cookies with the path /.
  • Request headers passed to LoadUrl are sent with the main request only, not with redirects or sub-resources.
  • File chooser requests (<input type="file">) are always cancelled.
  • No fullscreen video, no WebXR, no geolocation.
  • Ignore certificate errors only takes effect in development builds.
  • The engine version is the device's. Old devices with an outdated WebView may lack newer web features. WebView.EngineVersion is empty on Android.

Limits of texture mode.

  • CSS pixels follow the screen density. pixelDensity is ignored; a 1280 pixel wide texture on a dense phone gives a narrow layout. Use Zoom (applied as CSS zoom) or a viewport meta tag to tune it.
  • Textures are capped at 4096 pixels per side.
  • Left button and touch only. No right or middle button, and no cursor shape events.
  • Native popups don't show. The lists of <select> elements, date pickers and other controls that Android draws in its own windows aren't part of the page drawing. Use HTML controls in pages meant for texture mode.

Limits of overlay mode.

  • The page is always above everything Unity draws. Unity UI can't sit on top of it.
  • It is an axis-aligned rectangle: no rotation, no perspective, no masks, no 3D.
  • It isn't part of the rendered image, so it doesn't work in VR.
  • Unity receives no touches inside it, and the on-screen keyboard component doesn't serve it.
Meta Quest and other Android headsets

Use texture mode with WebViewScreen, a WebViewPointer in Transform mode on the controller, and the On-Screen Keyboard in World mode. Native overlays and the system keyboard aren't visible inside the headset view.

iOS

How it works. The package uses WKWebView, the only browser engine iOS offers to apps. Two modes exist:

  • Texture (the default). The web view is kept off-screen. The package takes snapshots of it and uploads them into a Unity texture, and replays your pointer and keyboard input in the page with JavaScript, because iOS has no way to send synthetic touches to a view.
  • Native Overlay. The WKWebView is placed on top of the Unity view. Full speed, real touch input, video, the system keyboard.
Choose the mode by content

Texture mode on iOS suits pages that are mostly still: text, forms, menus, dashboards, a HUD. For video, animation-heavy pages, WebGL content, or sites you don't control, use Native Overlay.

RequirementsiOS 13 or newer. Zoom and pixel density need iOS 14. Built with Xcode as usual; no framework or CocoaPods dependency is added.
Plain httphttp:// pages need an App Transport Security exception in the Info.plist. Player Settings > Allow downloads over HTTP adds one.
Camera and microphoneFill in Camera Usage Description and Microphone Usage Description in the Player Settings. With Camera and microphone on and a description missing, a check warns you before the build.
Developer toolsNo DevTools window. In development builds on iOS 16.4 or newer, pages can be inspected with Safari's Web Inspector on a Mac.

Limits of texture mode.

  • About 10 to 30 frames per second, depending on the device and the size of the texture. Taking a snapshot costs time on the main thread, so a page that animates all the time lowers the frame rate of the game. Keep textures small and lower Frame Rate.
  • HTML5 video is not visible in the texture; its sound plays. The same goes for DRM video. Use Native Overlay.
  • WebGL canvases may be missing from the snapshots.
  • Input is simulated. Events created by script have isTrusted false. Sites that check it (some login pages, payment forms, captchas) reject the input. The CSS states :hover and :active don't follow the pointer. HTML5 drag and drop and selecting text by dragging don't work.
  • No text caret and no selection highlight are drawn. Typing works; you don't see where the caret is.
  • No IME composition and no autofill. Chinese, Japanese and Korean input methods can't compose into the page.
  • <select> elements are shown as a list inside the page instead of the iOS picker. Date, time and colour inputs are not supported.
  • Before iOS 14, frames that show another site (an embedded video player, a payment widget) don't receive input, and copying text from the page to the clipboard is off. From iOS 14 on both work.

Limits in both modes.

  • Sound plays through iOS, not through Unity audio: no WebViewAudio, no 3D sound. Muted is best effort: it silences media elements the package can reach from script. IsPlayingAudio and AudioStateChanged don't report.
  • Downloads are reported through DownloadRequested and never saved.
  • Request headers passed to LoadUrl are sent with the first main request only.
  • Ignore certificate errors only takes effect in development builds.
  • Engine. Every iOS browser engine is WebKit. Pages that only work in Chromium won't work here. WebView.EngineVersion is empty on iOS.

Limits of overlay mode. As on Android: always above Unity, an axis-aligned rectangle, and Unity gets no input inside it. Elements can go fullscreen from iOS 15.4.

macOS

Preview

macOS support is new in this version and marked as a preview. Test your pages on a Mac before you rely on it, and report what you find.

How it works. On macOS 11 or later the package uses WKWebView, the engine of Safari, through the plugin Runtime/MacOS/UltimateWebViewMac.dylib (Intel and Apple Silicon in one file). It shares its code with iOS and behaves the same way, in builds and in the Editor:

  • Texture (the default). The web view sits invisibly inside the game window, snapshots of it are uploaded into a Unity texture, and your pointer and keyboard input is replayed in the page with JavaScript.
  • Native Overlay. The WKWebView is placed on top of the game view, with the real mouse and keyboard. In the Editor the overlay is not lined up with the Game view; use it in builds.

Limits. Those of iOS: texture mode suits pages that are mostly still (about 10 to 30 frames per second, no video), simulated input has no hover styles, drag and drop or IME composition, and page sound plays through the system instead of Unity audio. Chromium is not used on macOS, so DevTools, extra engine arguments, hardware acceleration and the sandbox setting don't apply; Safari's Web Inspector attaches to development builds on macOS 13.3 or later. An older macOS can't load the plugin: WebView.IsSupported is false there and web views stay blank.

Signing. The library is signed ad hoc. When you sign and notarise your game, sign it together with the rest of the app, as you do for every other plugin.

WebGL

How it works. A game in a browser can't embed a second browser, and browsers don't let a page read the pixels of another site. So in WebGL builds a web view is an <iframe> that the package creates next to the Unity canvas and keeps positioned over the rectangle of your component, in perspective when the component is a tilted WebViewScreen. The player's own browser renders it and handles its input.

What that means.

  • Overlay only. RendersToTexture is false and Texture stays empty. The page is always above the canvas: Unity UI, 3D objects and post-processing can't cover or affect it. A screen behind a wall still shows its page, so hide such screens yourself (disable the component).
  • Sites can refuse. Many sites forbid being shown in a frame (X-Frame-Options, Content-Security-Policy: frame-ancestors). They report LoadFailed with code -27. Search engines, social networks, banks and most login pages are among them. Your own pages and pages made for embedding work.
  • https games need https pages. A game served over https can't show an http:// page, except from localhost.
  • Only web addresses. http, https, about, data and blob addresses load. streaming-assets:// addresses resolve to the StreamingAssets folder next to the build on your web server.

Same origin and other origins. A page served from the same origin as the game (same scheme, host and port), a StreamingAssets page or a LoadHtml page is fully scriptable. For pages of other origins the browser draws a hard line:

FeatureSame originOther origin
ExecuteJavaScript, EvaluateJavaScriptYesNo a warning is logged, the error callback runs
window.uwv, startup scriptYesNo
MessagesYesBy handshake see below
Title, address changes inside the frameYesNo
Scroll, TypeText, edit commands, MutedYesNo

A page of another origin that you control can still exchange messages with the game. It uses the browser's own postMessage:

// In the page (other origin). Page to Unity: arrives in WebView.MessageReceived.
window.parent.postMessage({ uwvMessage: 'hello from the page' }, '*');

// Unity to page: what WebView.PostMessage sends.
window.addEventListener('message', function (e) {
    if (e.data && e.data.uwvMessage !== undefined) console.log(e.data.uwvMessage);
});

Other limits.

  • Pointer and keyboard input belong to the browser. PointerMove, PointerDown, PointerUp and Click do nothing, the pointer and keyboard components don't serve iframes, and Unity gets no input while the mouse is over the page.
  • WebViewData does nothing: cookies and storage belong to the player's browser. Third-party cookie rules of that browser apply to pages in frames.
  • No dialog, download, popup, cursor or crash events. LoadUrl headers are ignored. FrameRate is ignored.
  • No Unity audio. Sound plays in the browser, under its autoplay rules.
  • The iframe follows the canvas. Custom HTML templates that transform or reparent the canvas can misplace it; keep the canvas in a positioned container.

8Performance

A web view costs in three places: the browser engine renders the page, the finished frame is copied to Unity, and Unity uploads it to the GPU. The first cost depends on the page, the other two on the number of pixels and on how often the page changes. A page that doesn't change costs nothing per frame.

LeverWhereEffect
Texture sizeResolution, Resolution Scale, the size of the rect or elementThe biggest lever. Every repaint moves width x height x 4 bytes: 3.7 MB at 1280 x 720, 33 MB at 3840 x 2160. Size the texture for how large the page appears on screen, not for the resolution of the display.
Frame rateOptions > Frame Rate, WebView.FrameRateCaps repaints per second. 30 halves the cost of an animated page and is enough for most UI. 60 is the maximum.
What the page doesYour HTML and CSSA blinking cursor, a spinner, a CSS animation or a video forces repaints all the time. Remove idle animations from pages used as game UI.
PausingWebView.Rendering, Pause When Not Visible, Pause When DisabledA paused page isn't painted at all. Scripts and sound keep running unless you mute it.
Pixel densityOptions > Pixel DensityChanges how much layout fits into the same texture. Below 1 gives a larger layout for the same cost, with softer text.
Hardware accelerationSettingsOff by default, which is the cheaper path for text and ordinary layouts. Turn it on when pages use WebGL, large canvases or high-resolution video.
Mip mapsOptions > Mip MapsRebuilds the mip chain on every repaint. Worth it for screens seen at a distance or an angle in 3D; leave it off for UI.
Number of web viewsYour sceneEach web view is a browser tab with its own renderer process and memory. Dispose web views you no longer show, and reuse one web view with LoadUrl where you can.

Start-up. The engine starts with the first web view. On Windows and Linux that takes about a second, during which the texture is empty. Call WebView.Prewarm() in a loading screen, or create the web view early and show it when LoadFinished arrives.

A screen in the distance. A 1280 pixel wide texture on a monitor that covers 200 pixels of the view wastes most of its pixels. Lower the resolution, turn on Mip Maps if the text shimmers, and turn on Pause When Not Visible.

A full-screen HUD. At 1920 x 1080 every repaint is 8 MB. Keep the page still between updates: change text and numbers when the game state changes instead of animating them every frame. If only a corner of the HUD is animated, give it its own small web view.

Mobile. On Android, texture capture runs on the GPU and is fast, but the copy to Unity still depends on the size. On iOS, texture mode is slow by design of the platform: keep textures small, cap the frame rate at 15 to 30, and switch to Native Overlay for anything that moves a lot.

Memory. The engine on Windows and Linux uses a few hundred megabytes of RAM once pages are open, more with heavy sites. That memory belongs to the helper processes and doesn't show in Unity's profiler. Budget for it on machines with little RAM.

9Building and shipping

Builds need no manual step. This section says what the package adds to each build, what it costs in size, and what to check before release.

Windows and Linux builds

After Unity has built a Windows x64 or Linux x64 player, a build step copies the engine next to it:

MyGame.exe
MyGame_Data/
    UltimateWebView/
        UltimateWebViewHost.exe      the helper process (UltimateWebViewHost on Linux)
        libcef.dll                   Chromium (libcef.so on Linux)
        chrome_elf.dll, d3dcompiler_47.dll, vk_swiftshader.dll, vulkan-1.dll
        icudtl.dat, v8_context_snapshot.bin, vk_swiftshader_icd.json
        resources.pak, chrome_100_percent.pak, chrome_200_percent.pak
        locales/en-US.pak
  • Ship the whole folder. Every file is needed. Installers, launchers and store uploads must keep MyGame_Data/UltimateWebView as it is.
  • The source is the Engine folder of the package: Engine/Windows/x86_64 or Engine/Linux/x86_64. The build step renames the helper from UltimateWebViewHost.uwv to its real name.
  • Cross-building works. You can build the Linux player from the Windows Editor and the other way round.
  • Custom build pipelines. If the step can't find the data folder of the build, it logs a warning that names the folder to copy. Copy it to <Game>_Data/UltimateWebView yourself and rename the helper.
  • 32-bit Windows builds get no engine and log 32-bit Windows players are not supported. Web views stay blank in this build; switch the architecture to x86-64.
  • One engine per build. If you only target one desktop platform and never open the project in the Editor of the other, you can delete the other platform's folder from Engine. The Status card of the settings page shows which engines are present.

Licence files. The engine is open-source software, and its licences ask that their text travels with the binaries. The build step copies CEF_LICENSE.txt and Chromium_CREDITS.html into MyGame_Data/UltimateWebView/Licenses of every Windows and Linux build. Leave them there when you package the game; you can also show them behind a button in your credits. See section 12.

Code signing. The helper isn't signed. If you sign your Windows build, sign MyGame_Data/UltimateWebView/UltimateWebViewHost.exe with the same certificate. The Chromium libraries can stay as they are.

Player data. At run time the engine writes its profile to UltimateWebView in Application.persistentDataPath. Nothing is written into the game folder.

Android, iOS and WebGL builds

These builds contain no browser engine, only the bridge to the one on the device.

TargetWhat is addedWhat you do
AndroidJava sources compiled by Gradle, and the manifest entries listed in the Android chapter.Nothing for plain pages. Request camera and microphone permissions at run time if pages use them. If you maintain a custom main manifest with a networkSecurityConfig, allow cleartext there if you load http:// pages.
iOSOne Objective-C++ source file in the Xcode project. It uses WebKit, which is part of iOS.Fill in the camera and microphone usage descriptions if pages use them. Allow http in the Player Settings if you load http:// pages.
WebGLOne JavaScript library linked into the build.Serve the game over https if it shows https pages. Check that the sites you show allow framing. Pages in StreamingAssets are served by your web server with the build.

The Engine folder is never part of an Android, iOS or WebGL build.

Size and version control

ItemSizeWhere it counts
Windows engineAbout 335 MB, of which libcef.dll is 281 MBThe project, and every Windows build
Linux engineAbout 305 MBThe project, and every Linux build
Codec filesAbout 326 MB for Windows and 307 MB for LinuxThe project only. With H.264, AAC and HEVC on they replace their standard namesakes, so a build stays the same size.
Editor copyThe size of one engineLibrary/UltimateWebView, once per project
Scripts, plugins, demoA few megabytesThe project. Mobile and WebGL builds grow by well under a megabyte.

The engine compresses to less than half: about 160 MB for Windows and 140 MB for Linux in a zip archive, and similar in a store download.

Version control. libcef.dll and libcef.so are larger than the 100 MB per-file limit of GitHub and of several other hosts. Track the engine with Git LFS:

# .gitattributes
Assets/HyTeKGames/UltimateWebView/Engine/** filter=lfs diff=lfs merge=lfs -text

If you never turn on H.264, AAC and HEVC, you can delete the two Codecs folders. The settings page then warns you if the setting is switched on.

The alternative is to keep the Engine folder out of the repository and import it from the package on each machine. The scripts compile without it; web views stay blank and the Console says the engine is missing. Plastic SCM and Perforce handle the files as they are.

Before you ship

  1. Test on the real target. The Editor always shows Chromium; Android, iOS and WebGL use other engines with other limits.
  2. Set Remote debugging port to 0 and turn Ignore certificate errors off. Remove development switches from Extra engine arguments.
  3. Decide what your game does when a page fails to load (offline players): keep the built-in error page, or handle LoadFailed.
  4. Decide what popups and downloads do: see section 4.
  5. Windows and Linux: add the two licence files to the build and credit the Chromium Embedded Framework. Sign the helper if you sign the game.
  6. Windows and Linux: check your videos. MP4 with H.264 plays only with H.264, AAC and HEVC on, and then you are responsible for the patent licences; WebM always plays.
  7. Android and iOS: request camera and microphone permissions and fill in the usage descriptions, if pages use them.
  8. If your pages show content from the open web, say so in your store listing and privacy policy where the store asks for it. The package itself collects nothing and contacts no server of its own. With DRM (Widevine) on, the engine contacts Google's component update servers to get and update the Widevine module.

10Scripting reference

Every public type of the package, with every public member. All types are in the namespace HyTeKGames.UltimateWebView and in the assembly of the same name. Call everything from the main thread; every event and callback is raised there.

TypeKindPurpose
WebViewclassOne browser instance: texture, navigation, input, JavaScript.
WebViewOptionsclassSettings of one web view, read at creation.
ScriptDialog, LoadError, ConsoleMessage, InputFocus, DownloadRequest, WebCookie, WebViewExceptionclasses and structsData carried by events and calls.
WebViewDatastatic classCookies and stored data.
UltimateWebViewSettingsScriptableObjectProject-wide settings.
WebViewComponent, WebViewScreen, WebViewImage, WebViewPointer, WebViewAudio, IWebViewPointerTarget, WebViewCursors, WebViewStringEventcomponents and helpersDisplay, pointer and sound.
WebViewElementVisualElementA web view in UI Toolkit.
WebViewKeyboard, KeyboardElementcomponent, VisualElementThe on-screen keyboard.
EnumsenumsWebKey, KeyModifiers, PointerButton, WebViewCursor and the others.

WebView

public sealed class WebView : IDisposable. A web page rendered by the browser engine of the platform. Points are normalised, (0, 0) top-left and (1, 1) bottom-right. Calls made before IsReady are queued and replayed.

Constructors

WebView(int width, int height, string url)Creates a web view with default options and loads url.
WebView(int width, int height, WebViewOptions options = null)Creates a web view. The options are copied; later changes to your object have no effect. Width and height are texture pixels, clamped to 16 and to the smaller of 8192 and the device limit.

Static members

const string VersionThe package version, "1.1.0".
static bool IsSupported { get; }True when this platform has a browser engine. Where it is false, web views can be created and stay blank.
static string EngineVersion { get; }Windows and Linux: the engine version, for example "Chromium 156.0.8078.88". Empty until the engine has started, and on other platforms.
static WebView Focused { get; }The web view that has keyboard focus, or null.
static bool IsEditingText { get; }True while the focused web view has a text field in focus. Use it to hold back game shortcuts.
static IList<WebView> All { get; }Every live web view. Read-only.
static event Action<WebView> CreatedRaised for every new web view, at the end of its constructor.
static event Action<WebView> FocusedChangedKeyboard focus moved. The argument is the newly focused web view, or null.
static void Prewarm()Starts the browser engine now instead of with the first web view. Does nothing on platforms where the engine needs no start-up.
static string StreamingAssetsUrl(string relativePath)The address of a file in StreamingAssets that works on this platform, to pass to LoadUrl.

Properties

int Id { get; }A number unique to this web view for the session.
Texture Texture { get; }The page, upright. The same object for the whole life of the web view, also across Resize.
int Width { get; }
int Height { get; }
The size in texture pixels.
float PixelDensity { get; }Texture pixels per page pixel.
string Url { get; }The address of the current page.
string Title { get; }The title of the current page.
bool IsLoading { get; }True from LoadStarted until LoadFinished or LoadFailed.
float Progress { get; }Load progress, 0 to 1.
bool CanGoBack { get; }
bool CanGoForward { get; }
Whether the history has an entry in that direction.
bool IsReady { get; }True once the engine has created the browser.
bool IsDisposed { get; }True after Dispose. A disposed web view ignores every call.
WebViewCursor Cursor { get; }The cursor the page asks for at the pointer position.
InputFocus InputFocus { get; }The text field that has focus inside the page, if any.
bool IsPlayingAudio { get; }Windows and Linux: true while the page makes sound.
bool IsFocused { get; }True when this web view is WebView.Focused.
bool RendersToTexture { get; }False when the engine shows the page over the screen instead of drawing it into Texture: always in WebGL, and on Android and iOS with WebViewRenderMode.NativeOverlay.
bool HardwareKeyboard { get; set; }Whether the physical keyboard types into this web view while it has focus in play mode. Default true.
bool Muted { get; set; }Silences the page.
float Zoom { get; set; }Page zoom, 0.25 to 5. 1 is the normal size.
string StartupScript { get; set; }JavaScript run in every page before its own scripts. A change applies from the next page load.
int FrameRate { get; set; }Upper limit of repaints per second, 1 to 60.
bool Rendering { get; set; }False stops painting. The texture keeps its last image; scripts and sound of the page keep running.

Events

event Action ReadyThe engine has created the browser.
event Action<string> UrlChangedThe address changed, by navigation or by the page's own history calls.
event Action<string> TitleChangedThe title changed.
event Action<string> LoadStartedThe main document started loading. The argument is its address.
event Action<string> LoadFinishedThe main document and its resources finished loading.
event Action<LoadError> LoadFailedThe main document could not be loaded. Raised before the error page is shown.
event Action<float> ProgressChangedLoad progress, 0 to 1.
event Action NavigationStateChangedIsLoading, CanGoBack or CanGoForward changed. Use it to refresh toolbar buttons.
event Action<string> MessageReceivedThe page called uwv.postMessage. Objects arrive as JSON text.
event Action<ConsoleMessage> ConsoleMessageThe page wrote to the JavaScript console.
event Action<WebViewCursor> CursorChangedThe page asks for another cursor. Windows, Linux and iOS.
event Action<InputFocus> InputFocusChangedA text field took or lost focus inside the page.
event Action<string> PopupRequestedThe page tried to open a new window. The argument is the address. What happens next depends on WebViewOptions.popups.
event Action<ScriptDialog> DialogOpenedThe page called alert, confirm or prompt, or asks before unloading. With a listener the page waits for Accept or Cancel. Without one, dialogs are accepted and alerts are logged.
event Action<DownloadRequest> DownloadRequestedThe page started a download. Nothing is saved.
event Action CrashedThe process that renders the page, or the whole browser engine, ended unexpectedly. Script state of the page is lost; with Restart after crash on, the page is loaded again.
event Action<bool> AudioStateChangedWindows and Linux: the page started (true) or stopped (false) making sound.
event Action FrameUpdatedThe texture received a new frame.
event Action TextureResizedThe texture changed size after Resize.
event Action DisposedThe web view was disposed.

Navigation

void LoadUrl(string url)Loads an address. See the table in section 4 for how incomplete addresses are read.
void LoadUrl(string url, IDictionary<string, string> headers)Loads an address with extra HTTP headers on the page request. Not in WebGL; main request only on Android and iOS.
Task<bool> WaitForLoadAsync()Completes when the page that is loading, or the next one, has finished: true after LoadFinished, false after LoadFailed or when the web view is disposed. Call it right after starting a load; on a page that is already loaded it waits for the next one.
void LoadHtml(string html, string baseUrl = null)Shows a page from a string. baseUrl resolves relative links and sets the origin; null uses https://app.localhost/.
void Reload()Loads the current page again. While the error page is shown, retries the address that failed.
void Stop()Stops the load in progress.
void GoBack()
void GoForward()
Moves through the history.
void Dispose()Closes the browser and frees the texture. Safe to call twice.

Size and overlay

void Resize(int width, int height)Changes the texture size and reflows the page. The old image stays until the page has been painted at the new size.
void Resize(int width, int height, float pixelDensity)The same, with a new pixel density (0.5 to 4).
void SetOverlayRect(Rect screenRect)Overlay engines: places the page on screen. Screen pixels, origin bottom-left, as Input.mousePosition. Does nothing for texture web views.
void SetOverlayQuad(Vector2 topLeft, Vector2 topRight, Vector2 bottomRight, Vector2 bottomLeft)Overlay engines: places the page on four screen points. WebGL follows the quad in perspective; Android and iOS use its bounding rectangle.
void HideOverlay()Overlay engines: takes the page off the screen until the next SetOverlayRect or SetOverlayQuad.

The components and WebViewElement call the overlay methods for you. You need them only for a WebView you manage yourself.

JavaScript

void ExecuteJavaScript(string script)Runs a script in the main frame of the page.
void EvaluateJavaScript(string script, Action<string> onResult, Action<string> onError = null)Runs a script and reports the value of its last expression as JSON. onError receives the message when the script throws or the result can't be converted.
Task<string> EvaluateJavaScriptAsync(string script)The awaitable form. Throws WebViewException on failure.
void PostMessage(string message)Sends a string to the page. Listeners added with uwv.addEventListener('message', ...) receive it as event.data.

Pointer

void PointerMove(Vector2 point, KeyModifiers modifiers = KeyModifiers.None)Moves the pointer. Drives hover, and drags while a button is down.
void PointerLeave()Tells the page the pointer left it, which ends hover states.
void PointerDown(Vector2 point, PointerButton button = PointerButton.Left, KeyModifiers modifiers = KeyModifiers.None)Presses a button and gives the web view keyboard focus. Two or three presses in quick succession at the same place count as a double or triple click.
void PointerUp(Vector2 point, PointerButton button = PointerButton.Left, KeyModifiers modifiers = KeyModifiers.None)Releases a button.
void Click(Vector2 point, PointerButton button = PointerButton.Left)Move, press and release in one call.
void Scroll(Vector2 point, Vector2 delta, KeyModifiers modifiers = KeyModifiers.None)Scrolls what is under point. delta is in page pixels: positive y moves down the page, positive x to the right.

Keyboard and editing

void Focus()Gives this web view keyboard focus. The previously focused web view loses it.
void Blur()Takes keyboard focus away.
void KeyDown(WebKey key, KeyModifiers modifiers = KeyModifiers.None)Presses a key. Keys that print a character also type it, unless Control, Alt or Meta is held.
void KeyUp(WebKey key, KeyModifiers modifiers = KeyModifiers.None)Releases a key.
void SendKey(WebKey key, KeyModifiers modifiers = KeyModifiers.None)KeyDown followed by KeyUp.
void TypeText(string text)Types text into the focused field. Characters found on a keyboard are sent as key presses, so pages that listen to key events react. Everything else (accents, emoji, other scripts) is inserted directly.
void Undo() void Redo()
void Cut() void Copy() void Paste()
void DeleteSelection() void SelectAll()
Editing commands on the focused field or the selection. Cut, copy and paste use the system clipboard.
void OpenDevTools()Windows and Linux: opens the Chromium developer tools for this page in their own window.

WebViewOptions

[Serializable] public sealed class WebViewOptions. Read once when a web view is created. The Inspector shows these fields under Options.

string url = ""The page loaded at start. Empty starts blank.
WebViewRenderMode renderMode = TextureTexture or native overlay. Windows and Linux always use a texture, WebGL always an overlay.
bool transparentPages without a background colour are see-through.
int frameRate = 60Upper limit of repaints per second, 1 to 60.
float pixelDensity = 1fTexture pixels per page pixel, 0.5 to 4.
bool mutedStarts with the sound off.
bool unityAudio = trueWindows and Linux: page sound plays through a Unity AudioSource.
bool incognitoCookies and storage of this web view stay in memory. Ignored on Android and in WebGL.
PopupMode popups = OpenInSameViewWhat happens when a page opens a new window.
string startupScript = ""JavaScript run in every page before its own scripts.
bool errorPage = trueShows a short message in the page when an address can't be loaded.
bool mipMapsGenerates mip maps for the texture on every repaint.
WebViewOptions Clone()Returns a copy.

Data types

ScriptDialog

public sealed class ScriptDialog. A JavaScript dialog waiting for an answer. Passed to WebView.DialogOpened.

DialogType Type { get; }Alert, confirm, prompt or before-unload.
string Message { get; }The text of the dialog.
string DefaultText { get; }The suggested answer of a prompt.
string Url { get; }The address of the page that opened it.
bool IsAnswered { get; }True once Accept or Cancel was called. Later calls do nothing.
void Accept(string text = null)Answers OK. text is the value a prompt returns; null answers with DefaultText. Other dialog types ignore it.
void Cancel()Answers Cancel.

LoadError

public struct LoadError. Passed to WebView.LoadFailed.

string urlThe address that failed.
int codeThe error code of the engine. On Windows and Linux these are Chromium network error codes (for example -105, name not resolved; -106, no internet connection). Other engines report their own codes or Failed.
string descriptionA readable reason.
const int Failed = -2The code used when the engine gives no specific one.
override string ToString()Address, code and description in one line.

ConsoleMessage

public struct ConsoleMessage. Passed to WebView.ConsoleMessage.

ConsoleLevel levelDebug, info, warning or error.
string textThe message.
string sourceThe address of the script that logged it.
int lineThe line in that script.
override string ToString()Level, text, source and line in one line.

InputFocus

public struct InputFocus. The text field that has focus inside a page.

bool editableTrue while a text field has focus.
string typeThe kind of field: "text", "password", "email", "number", "search", "tel", "url", "textarea" or "contenteditable".
bool IsNumeric { get; }True for number and telephone fields. The keyboard shows its numeric pad.

DownloadRequest

public struct DownloadRequest. Passed to WebView.DownloadRequested.

string urlThe address of the file.
string suggestedFileNameThe file name the server or the page suggests.
string mimeTypeThe content type, when known.

WebCookie

[Serializable] public struct WebCookie.

string name
string value
Name and value.
string domainThe domain the cookie belongs to, for example example.com.
string pathThe path the cookie is sent to, usually /.
bool secureSent over https only.
bool httpOnlyHidden from page scripts.
double expiresExpiry in seconds since 1 January 1970 UTC. 0 makes a session cookie.

WebViewException

public sealed class WebViewException : Exception. Thrown by EvaluateJavaScriptAsync when the script fails. Message holds the JavaScript error. Constructor: WebViewException(string message).

WebViewData

public static class WebViewData. Cookies and stored data of the browser profile that all web views share. Does nothing in WebGL builds.

static void ClearAll()Deletes cookies, the HTTP cache, local storage, IndexedDB and service workers. On Windows and Linux the engine restarts and open pages reload.
static void ClearCookies()Deletes every cookie.
static void ClearCache()Empties the HTTP cache.
static void SetCookie(string url, WebCookie cookie)Stores a cookie for the site at url. Ignored when the address or the cookie name is empty.
static void GetCookies(string url, Action<WebCookie[]> callback)Reads the cookies that would be sent to url. The callback always runs, with an empty array when there are none.
static void DeleteCookies(string url, string name = null)Deletes one cookie of url, or all of them when name is left out.

UltimateWebViewSettings

public sealed class UltimateWebViewSettings : ScriptableObject. The project-wide settings of section 6. They are read when the browser engine starts.

static UltimateWebViewSettings Instance { get; }The settings in use: the asset in a Resources folder, or an object with default values when the project has none.
const string ResourceName"UltimateWebViewSettings", the name the asset is loaded by.
bool hardwareAccelerationWindows and Linux: GPU compositing, WebGL and video decoding. Default false.
bool persistentStorage = trueKeeps cookies, storage and cache between sessions.
bool allowAutoplay = trueMedia starts without a click.
bool allowCameraAndMicrophoneGrants camera and microphone requests of pages. Default false.
bool allowFileAccessLocal pages can read other local files with fetch, XHR and modules. Default false.
bool sandbox = trueWindows: page content runs inside the Chromium sandbox.
bool proprietaryCodecsWindows and Linux: runs the engine build with H.264, AAC and HEVC. Default false. Read when the Editor starts the engine and when a player is built.
bool drmWidevine for protected media on Windows, Linux and Android. On Windows and Linux protected video stays black in the texture. Default false.
string homePageFirst page of the Browser window. Default https://www.google.com/.
string searchUrlSearch address with {0} for the text. Default Google.
static string SearchAddress(string text)The search address for text, escaped.
bool ignoreCertificateErrorsLoads pages with invalid HTTPS certificates. Development only.
bool systemKeyboard = trueAndroid and iOS: opens the system keyboard for text fields of texture web views.
string userAgent = ""Replaces the User-Agent header. Empty keeps the engine default.
int remoteDebuggingPortPort for Chrome DevTools. 0 turns it off.
string[] engineArgumentsWindows and Linux: extra Chromium command line switches, one per entry.
bool restartAfterCrash = trueWindows and Linux: restarts the engine and reloads the open pages after a crash.
EngineLogLevel engineLog = ErrorsWhich engine messages reach the Unity Console.
bool logPageConsoleWrites the JavaScript console of every page to the Unity Console.

Components

WebViewComponent

public abstract class WebViewComponent : MonoBehaviour. The base of WebViewScreen and WebViewImage: owns a WebView, keeps its size up to date and raises the Inspector events. Derive from it to show a web view on something else.

WebView WebView { get; }The web view. Null until the component is first enabled in play mode, and after it is destroyed.
WebViewOptions Options { get; set; }The options. Changes made after the web view exists apply to the next one only.
string Url { get; set; }Get: the current address, or the start address before the web view exists. Set: loads the address.
bool Interactive { get; set; }Whether pointers reach the page. Turning it off releases held buttons and hover.
event Action<WebView> CreatedThe web view was created. Subscribe to its events here. Components wake up in no particular order, so the web view may already exist when your script starts: check WebView as well, as the recipes do.
void LoadUrl(string url)Loads an address. Before the web view exists, the address becomes the start page.
void LoadHtml(string html)Shows a page from a string. Before the web view exists, it becomes the start page.
void Reload() void GoBack() void GoForward()Forwarded to the web view. They are shaped for UnityEvents, as are the methods above and below.
void ExecuteJavaScript(string script)Runs a script in the page. Ignored before the web view exists.
void PostMessage(string message)Sends a string to the page. Ignored before the web view exists.

Protected members, for your own display components:

abstract Vector2Int GetTextureSize()Return the texture size you want. Called every frame; a change resizes the web view after a short delay.
abstract void ShowTexture(Texture texture)Put the texture on your surface. Called with null when there is nothing to show (overlay engines, destruction).
abstract bool GetScreenCorners(out Vector2 topLeft, out Vector2 topRight, out Vector2 bottomRight, out Vector2 bottomLeft)Report where the surface is on screen, in pixels with the origin bottom-left. Used to place overlay engines. Return false while the surface is not on screen.
virtual void OnWebViewCreated(WebView webView)Called once the web view exists, before Created.
virtual void OnInteractionStopped()Called when Interactive turns off or the component is disabled. Release what you hold.
bool CanInteract { get; }True when the component is enabled, interactive and has a live web view.
void SetVisible(bool value)Tell the base class whether anybody can see the surface. False pauses painting.
virtual void OnEnable() OnDisable() OnDestroy() LateUpdate()Unity messages used by the base class. Call the base method when you override one.

WebViewScreen

public sealed class WebViewScreen : WebViewComponent, IWebViewPointerTarget. A page on a mesh. Inherits everything above.

Vector2Int Resolution { get; set; }Texture size in pixels. With Match Aspect on, the height is derived.
float Brightness { get; set; }Multiplies the page colour in the package's screen shader.
Renderer TargetRenderer { get; set; }The renderer that shows the page.
bool PauseWhenNotVisible { get; set; }Stops painting while no camera sees the renderer.
bool IsInteractive { get; }IWebViewPointerTarget: whether the screen takes pointer input now.
WebViewCursor Cursor { get; }IWebViewPointerTarget: the cursor of the page.
bool TryGetPoint(RaycastHit hit, out Vector2 point)Converts a physics hit on the screen into a normalised page point. Use it for your own ray casts.
void PointerMove(Vector2 point, KeyModifiers modifiers)
void PointerDown(Vector2 point, PointerButton button, KeyModifiers modifiers)
void PointerUp(Vector2 point, PointerButton button, KeyModifiers modifiers)
void PointerScroll(Vector2 point, Vector2 delta, KeyModifiers modifiers)
void PointerExit()
IWebViewPointerTarget: pointer input, forwarded to the web view while the screen is interactive.

WebViewImage

public sealed class WebViewImage : WebViewComponent, with the EventSystem interfaces IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler, IScrollHandler, IBeginDragHandler, IDragHandler, IEndDragHandler, ISelectHandler and IDeselectHandler. A page in a uGUI RawImage. Only compiled when the Unity UI package is installed.

RawImage RawImage { get; }The image that shows the page.
float ScrollSpeed { get; set; }Multiplier of the wheel distance.
bool CursorIcons { get; set; }Whether the system cursor takes the shape the page asks for.
void OnPointerEnter(PointerEventData eventData)
void OnPointerExit(PointerEventData eventData)
void OnPointerDown(PointerEventData eventData)
void OnPointerUp(PointerEventData eventData)
void OnBeginDrag(PointerEventData eventData)
void OnDrag(PointerEventData eventData)
void OnEndDrag(PointerEventData eventData)
void OnScroll(PointerEventData eventData)
void OnSelect(BaseEventData eventData)
void OnDeselect(BaseEventData eventData)
Called by the EventSystem. You don't call them yourself.

WebViewPointer

public sealed class WebViewPointer : MonoBehaviour. Aims at pointer targets with a physics ray.

IWebViewPointerTarget Target { get; }The surface under the pointer, or the captured one. Null when there is none.
Vector2 Point { get; }The normalised point on the target.
bool IsOverTarget { get; }True while the pointer is on a surface.
Ray Ray { get; }The ray used in the last update. Draw your laser from it.
WebViewPointerMode Mode { get; set; }How the pointer aims.
Camera TargetCamera { get; set; }The camera of the Mouse, ScreenCenter and Virtual modes. Null uses the main camera.
Transform RayOrigin { get; set; }The origin of the ray in Transform mode. Null uses the pointer's transform.
bool ReadMouse { get; set; }Whether buttons and wheel are read from the mouse or the first finger.
bool DragScrolls { get; set; }Whether dragging scrolls instead of selecting.
WebViewPointerCursor CursorStyle { get; set; }How the cursor is shown.
event Action<IWebViewPointerTarget> TargetChangedThe pointer moved to another surface, or off every surface (null).
void Press(PointerButton button = PointerButton.Left)Presses a button at the current point. In Virtual mode the first press captures the surface.
void Release(PointerButton button = PointerButton.Left)Releases a button.
void Click()Press and release of the left button.
void Scroll(Vector2 pagePixels)Scrolls the surface under the pointer. Positive y moves down the page.
void Move(Vector2 normalizedDelta)Virtual mode: slides the cursor over the captured surface. (1, 1) is the full width and height; positive y moves down.
void Capture(IWebViewPointerTarget target)Virtual mode: locks the pointer to a surface. Null captures the surface under the view centre.
void ReleaseCapture()Virtual mode: lets the surface go.

WebViewAudio

public sealed class WebViewAudio : MonoBehaviour. Requires an AudioSource. Windows and Linux.

AudioSource AudioSource { get; }The source that plays the page.
WebView WebView { get; set; }The web view whose sound is played. Setting it is the same as Bind.
void Bind(WebView target)Plays the sound of target through this source. Null unbinds. A web view has one output at a time.

IWebViewPointerTarget

public interface IWebViewPointerTarget. A surface a WebViewPointer can aim at. Implement it on a component whose GameObject has a collider. WebViewScreen and WebViewKeyboard implement it.

bool IsInteractive { get; }False makes the pointer ignore the surface.
WebViewCursor Cursor { get; }The cursor to show over the surface.
bool TryGetPoint(RaycastHit hit, out Vector2 point)Convert a hit on your collider into a normalised point, (0, 0) top-left. Return false when the hit is outside the usable area.
void PointerMove(Vector2 point, KeyModifiers modifiers)The pointer moved over the surface.
void PointerDown(Vector2 point, PointerButton button, KeyModifiers modifiers)
void PointerUp(Vector2 point, PointerButton button, KeyModifiers modifiers)
A button was pressed or released.
void PointerScroll(Vector2 point, Vector2 delta, KeyModifiers modifiers)Scrolling, in page pixels. Positive y moves down.
void PointerExit()The pointer left the surface.

WebViewCursors

public static class WebViewCursors. The cursor images the package draws, 32 x 32 pixels, for use with UnityEngine.Cursor.SetCursor or in your own UI.

static Texture2D GetTexture(WebViewCursor cursor)The image of a cursor shape: white with a dark outline, readable RGBA32. Never null; WebViewCursor.None gives a fully transparent image.
static Vector2 GetHotspot(WebViewCursor cursor)The active point of that image, in pixels from its top-left corner.

WebViewStringEvent

[Serializable] public sealed class WebViewStringEvent : UnityEvent<string>. The type of the On Page Loaded and On Message events in the Inspector.

WebViewElement

public partial class WebViewElement : VisualElement. A web view as a UI Toolkit element. UXML name WebViewElement in the namespace HyTeKGames.UltimateWebView. Runtime panels need Unity 2021.2 or newer.

WebViewElement()Creates the element. The web view is created later, once the element is on a panel and has a size.
const string UssClassName"uwv-web-view", the USS class of the element.
string Url { get; set; }The address. Setting it loads the page. UXML attribute url.
bool Transparent { get; set; }Whether pages without a background are see-through. Applies to the next web view the element creates. UXML attribute transparent.
float PixelDensity { get; set; }Texture pixels per UI point, on top of the panel scale, 0.25 to 4. UXML attribute pixel-density.
bool Interactive { get; set; }Whether pointer and keyboard reach the page. UXML attribute interactive.
WebViewOptions Options { get; }The options for the web view the element creates. Change them before the element is on a panel. url, transparent and pixelDensity are overwritten by the element's own properties.
WebView WebView { get; set; }Get: the web view, created on demand when the element is on a panel and has a size; otherwise null. Set: shows a web view you own; the element never resizes or disposes it.
event Action<WebView> CreatedThe element created its web view.
void Dispose()Disposes the web view the element created. A web view you assigned is released, not disposed.

Before Unity 2023.2 the class also contains the nested types UxmlFactory and UxmlTraits, which UI Builder and UXML need. From 2023.2 on the element uses [UxmlElement] instead.

Keyboard

WebViewKeyboard

public sealed class WebViewKeyboard : MonoBehaviour, IWebViewPointerTarget. The on-screen keyboard component.

static bool IsOpen { get; }True while any on-screen keyboard of the package is visible.
bool IsVisible { get; }True while this keyboard is shown.
KeyboardMode Mode { get; }Overlay or world. Set in the Inspector.
KeyboardLayoutType Layout { get; set; }The layout.
WebView Target { get; set; }The web view that receives the keys. Null follows WebView.Focused.
bool LightTheme { get; set; }Light keys instead of dark ones.
bool ShowLayoutKey { get; set; }Whether the layout switch key is shown.
bool HideOnEnter { get; set; }Whether Enter in a single-line field hides the keyboard.
bool AutoShow { get; set; }Whether the keyboard follows text field focus.
KeyboardElement Element { get; }The UI Toolkit keyboard inside the component. Null on Unity 2020.3 and while the component is disabled.
event Action Shown
event Action Hidden
The keyboard appeared or went away.
void Show()
void Hide()
Shows or hides the keyboard, whatever the focus is.
bool IsInteractive { get; }
WebViewCursor Cursor { get; }
bool TryGetPoint(RaycastHit hit, out Vector2 point)
void PointerMove(Vector2 point, KeyModifiers modifiers)
void PointerDown(Vector2 point, PointerButton button, KeyModifiers modifiers)
void PointerUp(Vector2 point, PointerButton button, KeyModifiers modifiers)
void PointerScroll(Vector2 point, Vector2 delta, KeyModifiers modifiers)
void PointerExit()
IWebViewPointerTarget: how a WebViewPointer presses the keys in World mode.

KeyboardElement

public partial class KeyboardElement : VisualElement. The keyboard as a UI Toolkit control, for your own layouts. It types into the focused web view (or Target) and raises events for other uses. It never takes focus. UXML name KeyboardElement in the namespace HyTeKGames.UltimateWebView.

KeyboardElement()Creates the keyboard and loads its style sheet.
KeyboardLayoutType Layout { get; set; }The layout. UXML attribute layout.
WebView Target { get; set; }The web view that receives the keys. Null follows WebView.Focused.
bool NumericMode { get; set; }Shows the numeric pad whatever the field is. UXML attribute numeric-mode.
bool ShowLayoutKey { get; set; }Shows the layout switch key. UXML attribute show-layout-key.
bool ShowHideKey { get; set; }Shows the hide key. UXML attribute show-hide-key.
bool LightTheme { get; set; }Light keys. UXML attribute light-theme.
bool IsPressed { get; }True while at least one key is held.
event Action<string> TextEnteredText was typed, accents already combined.
event Action<WebKey, KeyModifiers> KeyPressedA key that isn't text was pressed: Backspace, Enter, Tab, arrows.
event Action HideRequestedThe hide key was pressed. The element doesn't hide itself.
event Action<KeyboardLayoutType> LayoutChangedThe user switched the layout.
void PointerDown(Vector2 localPosition, int pointerId)
void PointerMove(Vector2 localPosition, int pointerId)
void PointerUp(Vector2 localPosition, int pointerId)
void PointerCancel(int pointerId)
Presses keys from code, for pointers that don't come through UI Toolkit events, such as a ray in the scene. Positions are in element coordinates, origin top-left. Every pointer needs its own id. PointerCancel lets go of a key without typing it.
void ReleaseAll()Lets go of every held key, for example when you hide the keyboard.
const string UssClassName
const string LightUssClassName
const string KeyUssClassName
const string LabelUssClassName
const string HintUssClassName
const string IconUssClassName
The USS classes: uwv-keyboard, uwv-keyboard--light, uwv-keyboard__key, uwv-keyboard__label, uwv-keyboard__hint, uwv-keyboard__icon.

Before Unity 6 the class also contains the nested types UxmlFactory and UxmlTraits.

Enums

EnumValues
WebViewRenderModeTexture: the page is drawn into a texture. NativeOverlay: the engine places its own view over the game.
PopupModeOpenInSameView: the new address loads in the same web view. NotifyOnly: nothing loads; PopupRequested reports the address. Block: nothing happens.
PointerButtonLeft, Middle, Right.
KeyModifiersFlags: None = 0, Shift = 1, Control = 2, Alt = 4, Meta = 8. Combine with |.
DialogTypeAlert, Confirm, Prompt, BeforeUnload.
ConsoleLevelDebug, Info, Warning, Error.
EngineLogLevelOff, Errors, Warnings, Everything.
WebViewCursorDefault, Pointer, Text, Crosshair, Wait, Progress, Help, Move, NotAllowed, Grab, Grabbing, ResizeHorizontal, ResizeVertical, ResizeNESW, ResizeNWSE, ZoomIn, ZoomOut, None.
WebViewPointerModeMouse, ScreenCenter, Transform, Virtual. See section 4.
WebViewPointerCursorAuto: system cursor in Mouse mode when a mouse is present, drawn cursor otherwise. None: no cursor. Hardware: the system cursor takes the page's shape. World: a cursor is drawn on the surface.
KeyboardModeOverlay: docked to the bottom of the screen. World: a panel in the scene.
KeyboardLayoutTypeQwerty (English, United States), Azerty (French), Qwertz (German).
WebKeyKeys, with the values of Windows virtual key codes, which are also the keyCode values of JavaScript key events.
None, Backspace, Tab, Enter, Shift, Control, Alt, Pause, CapsLock, Escape, Space, PageUp, PageDown, End, Home, ArrowLeft, ArrowUp, ArrowRight, ArrowDown, PrintScreen, Insert, Delete,
Digit0 to Digit9, A to Z, Meta, ContextMenu,
Numpad0 to Numpad9, NumpadMultiply, NumpadAdd, NumpadSubtract, NumpadDecimal, NumpadDivide,
F1 to F12, NumLock, ScrollLock,
Semicolon, Equals, Comma, Minus, Period, Slash, Backquote, BracketLeft, Backslash, BracketRight, Quote.

JavaScript side

The object window.uwv exists in every page a web view loads (in WebGL builds: in pages of the game's origin).

uwv.postMessage(message)Sends a message to Unity. Strings are sent as they are; anything else goes through JSON.stringify. Raises WebView.MessageReceived and the On Message event.
uwv.addEventListener('message', listener)Adds a listener for messages from Unity. It receives an object with type ('message') and data (the string passed to PostMessage).
uwv.removeEventListener('message', listener)Removes a listener.
uwv.onmessageA single handler, called like a listener. Assign a function or null.
window event 'uwvready'Dispatched on window when the bridge has been installed. Listen for it when your script may run before the bridge exists.

The package also defines window.__uwvPost and a few other names starting with __uwv for its own use. Don't call or overwrite them.

11Troubleshooting and FAQ

Start with the Console. The package prefixes its messages with [Ultimate Web View] and says what is wrong and what to do. For more detail, set Engine log level to Everything and turn on Page console to Unity console in the settings.

The web view stays blank

  • Components create their web view in play mode. In edit mode a WebViewScreen or WebViewImage shows nothing.
  • Check WebView.IsSupported. It is false in 32-bit Windows builds, on a macOS older than 11 and on platforms the package doesn't cover.
  • Open Project Settings > Ultimate Web View. The Status card says whether the engine files are in the project and whether the engine runs.
  • The first frame takes about a second after the engine starts. An empty texture for a moment is normal; see WebView.Prewarm().
  • On a 3D screen, look at the object from the front: Unity's quad is invisible from behind.

The Console says the browser engine is missing or failed to start

  • The browser engine is missing: files of the Engine folder are absent. Reimport the package. If the project comes from Git, check that Git LFS pulled the real files and not pointer files of a few bytes.
  • The browser engine failed to start: something stopped the helper process. Security software that quarantined UltimateWebViewHost or libcef is the usual cause; restore the files and add an exception for the project.
  • On Linux, list the system libraries the engine can't find: ldd Library/UltimateWebView/Host-*/libcef.so | grep "not found".

It works in the Editor but the build shows nothing

  • Windows and Linux: check that <Game>_Data/UltimateWebView exists next to the executable and contains libcef and UltimateWebViewHost. A build script that moves the executable without its data folder, or an installer that filters .exe and .dll files, loses it.
  • Check the build log for a warning or an error from the package: 32-bit architecture, engine missing from the project, data folder not found.
  • The package writes its messages to the Player log of the build. Read it.
  • Android, iOS, WebGL: the device uses another engine than the Editor. Read the limits in section 7.

A video doesn't play

  • Windows, Linux and the Editor: MP4 with H.264 or AAC, HLS streams and Twitch need H.264, AAC and HEVC; without it, use WebM (VP8, VP9 or AV1 with Opus or Vorbis). HEVC also needs Hardware acceleration. Protected audio needs DRM (Widevine); protected video stays black in the texture even then, only its sound plays. Settings take effect at the next engine start.
  • iOS in texture mode: video is not visible. Use Native Overlay.
  • Android on API 21 and 22: no video in texture mode.
  • A video that waits for a click: turn on the Autoplay setting, or start it muted.

Clicks don't reach a 3D screen

  • The scene needs a WebViewPointer, and it must be enabled.
  • The screen needs a collider, on a layer that is in the pointer's Layers, closer than Max Distance, with no other collider on those layers in front of it.
  • Interactive must be on.
  • With Ignore When Over UI on, a uGUI element with Raycast Target that covers the screen area (a full-screen panel, even a transparent one) blocks the pointer.
  • In Mouse mode the pointer needs a camera: Target Camera, or a camera tagged MainCamera.

Clicks don't reach a Web View Image

It behaves like any uGUI element: the scene needs an EventSystem with an input module that matches your input backend, the canvas needs a GraphicRaycaster, Raycast Target must be on for the RawImage, and nothing with a raycast target may lie over it. A CanvasGroup with Blocks Raycasts off above it also stops input.

Clicks land in the wrong place on my mesh

For a MeshCollider the page point comes from the UV coordinates of the hit, which needs Read/Write enabled in the import settings of the mesh. Without it, and for every other collider type, the position inside the bounds of the mesh is used, which is only right when the screen surface fills those bounds. For a monitor model, make the screen its own flat mesh with UVs from 0 to 1, give it a MeshCollider, and put the WebViewScreen on it.

Typing does nothing

  • The web view needs keyboard focus: click a text field in the page, or call Focus() and click into the field with Click.
  • No on-screen keyboard shows up: the scene needs an On-Screen Keyboard object (GameObject > Ultimate Web View) with Auto Show ticked. On Android and iOS the keyboard of the system opens instead when no such component is enabled and System keyboard is on in the settings.
  • The physical keyboard is forwarded in play mode only, to web views with HardwareKeyboard on. In edit mode, use WebViewElement, which gets its keys from UI Toolkit.
  • With a WebViewPointer and Click Outside Blurs on, a click next to the screen takes focus away again.
  • A uGUI InputField that is selected takes the keys as well. Deselect it.

My game reacts while the player types into a page

Keys are not consumed. Check WebView.IsEditingText before you handle keyboard input, as in the input recipe. With the Input System, disable the action maps of your gameplay while it is true.

Text is blurry or shimmers

  • uGUI: keep Match Rect Size on and Resolution Scale at 1, so one texture pixel is one screen pixel.
  • 3D screens: raise Resolution until the texture has about as many pixels as the screen covers on the display. For screens seen small or at an angle, turn on Mip Maps.
  • Text too small to read on a large texture: raise Pixel Density or Zoom instead of lowering the resolution.

The page looks too dark, too bright or shaded

A screen is a surface in your scene, so post-processing, exposure and tone mapping apply to it. With the package's own shader, use Brightness to compensate (HDRP scenes with physical exposure often need a value above 1). If you assigned a lit material, scene lights shade the page: switch to an unlit shader, or leave the default material so the component uses its own.

There is no sound, or it isn't 3D

  • Check Muted in the options and the Autoplay setting. Without autoplay a page needs a click before it may play.
  • The scene needs an enabled AudioListener, and Mute Audio in the Game view must be off.
  • For 3D sound, the AudioSource next to the WebViewAudio needs Spatial Blend at 1.
  • Unity audio works on Windows and Linux, in play mode. On Android, iOS and WebGL the browser plays its own sound, always in 2D.

Messages between the page and C# get lost

  • PostMessage reaches the page that is loaded at that moment. Send after LoadFinished, or let the page ask first.
  • In the page, register the listener before you expect messages, and guard against a late bridge with the uwvready event.
  • WebGL: window.uwv doesn't exist in pages of other origins. Use the handshake.
  • MessageReceived delivers strings. An object sent from the page arrives as JSON text.

A site refuses to sign in or says the browser is not supported

Some sign-in providers and some sites reject browsers that run inside applications on purpose, on every platform and whatever the user agent says. Nothing in a web view can change that. For sign-in, use the flow those providers document for applications: open the system browser with Application.OpenURL and receive the result through a redirect to your own server or a local address. On iOS in texture mode, sites that test for trusted input events reject clicks; use Native Overlay there.

In a WebGL build a site doesn't load

The site forbids being shown in a frame, or it is an http:// page inside an https game. LoadFailed says which. Neither can be worked around from the game: the player's browser enforces both. Show your own pages, pages made for embedding, or open the address in a new browser tab with Application.OpenURL.

My page can't reach my local server

A page loaded from a string has the origin https://app.localhost. Requests to another origin follow the usual browser rules: the server must send CORS headers, and browsers restrict what a public page may request from the local network (the Windows and Linux engine switches that check off; Android, iOS and WebGL keep it). The reliable way is to load the page from the server itself, or to pass the server address as the base address of LoadHtml. During development on Windows and Linux, the engine argument disable-web-security switches the same-origin rules off; don't ship with it.

Pages reload when I change a script in play mode

That is expected. The engine stops at every script reload, because the C# side that talks to it is unloaded. Components create their web view again and go back to the page they were on; the state inside the page (scroll position, form content) is lost.

Security software flags UltimateWebViewHost

The helper is an unsigned program that starts child processes and opens network connections, which is what a browser does and also what some heuristics look for. It contains no code other than the Chromium Embedded Framework and the bridge to Unity. For your players, sign the helper in your build with your own certificate; signed files from a known publisher are rarely flagged.

A second instance of my game starts signed out

A browser profile can be open in one engine at a time. The second instance of the same game on the same machine runs from a temporary profile that is deleted when it closes. The same happens with two Editors on one project.

Can the engine be made smaller?

Not by removing files: every file in the engine folder is needed, and the language packs are already reduced to one. What you can do is ship one platform's engine per build (the build step does that), delete the engine of a desktop platform you don't target from the project, and rely on your store's compression, which brings the download to less than half.

How many web views can I have?

There is no fixed limit. Each web view is a browser tab with its own process and memory, tens of megabytes for a small page and far more for a heavy site. A handful at once is comfortable on desktop. Dispose the ones nobody sees, or pause them with Rendering = false if you want them back quickly.

Does it work in VR?

Yes, with pages as textures: WebViewScreen, a WebViewPointer in Transform mode on each controller, your trigger calling Press and Release, and the On-Screen Keyboard in World mode. That covers PC VR on Windows and Android headsets such as Meta Quest. Native overlays are never visible in a headset.

Can a page upload a file or open a file dialog?

No. File choosers are never opened, on any platform, and the page receives no file. If you need uploads, pick the file in Unity and send it with UnityWebRequest, or pass its content to the page with PostMessage.

How do I debug a page?

  • Windows, Linux and the Editor: webView.OpenDevTools(), or Developer Tools in the menu of the Browser window. Elements, console, network and sources work as in a desktop browser.
  • Without code: turn on Page console to Unity console.
  • Android: a development build, a USB cable and chrome://inspect.
  • iOS: a development build on iOS 16.4 or newer and Safari's Develop menu on a Mac.
  • WebGL: the developer tools of the browser; the page is an iframe in the document.

Is macOS supported?

As a preview. macOS 11 and later use WKWebView, the engine of Safari, in builds and in the Editor, with the abilities and limits of iOS: see macOS. Chromium is not used there. Test your pages on a Mac before you plan a macOS release around it.

What about consoles, UWP, tvOS or visionOS?

Not supported. The package compiles for them and web views stay blank, so a multi-platform project keeps building. Guard your UI with WebView.IsSupported.

How do I update or remove the package?

Update from the Package Manager; the Editor doesn't lock the engine files, so it can stay open. If an update removes or renames files, delete Assets/HyTeKGames/UltimateWebView first and import again. To remove the package, delete that folder, Assets/Resources/UltimateWebViewSettings.asset if you created settings, and Library/UltimateWebView.

12Third-party software

The scripts, shaders, style sheets, the Android, iOS and WebGL plugins and the helper program are written by HyTeKGames and licensed under the Unity Asset Store EULA. The browser engine for Windows and Linux in the Engine folder is open-source software with its own licences. The package contains no third-party fonts, images, sounds or script libraries.

ComponentLicenceFiles
Chromium Embedded Framework (CEF) 156.0.26BSD 3-Clauselibcef, chrome_elf.dll, the .pak files, and the CEF wrapper code inside the helper
Chromium 156.0.8078.88 and the components it bundlesBSD 3-Clause for Chromium. The bundled components have their own: BSD, MIT, Apache 2.0, MPL 2.0, ISC, zlib, Unicode, LGPL and others.Compiled into libcef
FFmpeg (as built by Chromium; the files in Codecs add its H.264 and AAC decoders)LGPL 2.1 or laterCompiled into libcef
OpenH264 (files in Codecs only, H.264 encoder for WebRTC)BSD 2-ClauseCompiled into libcef of Codecs
V8 JavaScript engineBSD 3-Clausev8_context_snapshot.bin, code in libcef
ICUUnicode Licenseicudtl.dat, code in libcef
SwiftShaderApache 2.0vk_swiftshader library and vk_swiftshader_icd.json
Vulkan LoaderApache 2.0vulkan-1.dll, libvulkan.so.1
Direct3D shader compilerMicrosoft redistributable, part of the CEF distributiond3dcompiler_47.dll

The details are in three files of the package:

  • Third-Party Notices.txt: every component with its version, copyright holder, licence and source address.
  • Licenses/CEF_LICENSE.txt: the licence of the Chromium Embedded Framework.
  • Licenses/Chromium_CREDITS.html: the complete list of the components inside Chromium with every licence text, as generated by the Chromium build.

What this means for your game. Windows and Linux builds contain these binaries. The build step puts CEF_LICENSE.txt and Chromium_CREDITS.html into MyGame_Data/UltimateWebView/Licenses; keep that folder in what you ship. Android, iOS and WebGL builds contain none of these components and need no notice.

About the LGPL parts. The LGPL code is inside libcef, a separate dynamic library that only the helper process loads. It isn't linked into your game or into the scripts of this package. You or your players may replace libcef and the files that belong to it with another build of the same CEF version, in the Engine folder before building or in <Game>_Data/UltimateWebView afterwards. The source code is available at the addresses listed in Third-Party Notices.txt.

13Support and changelog

Support

Discorddiscord.gg/teabRhGZYG (username iamtek). The fastest way to reach me.
Email[email protected]

A report I can act on contains:

  • the Unity version, the render pipeline and the package version (WebView.Version);
  • the platform where it happens: Editor or build, operating system, device model for mobile;
  • what you did, what you expected and what happened, with the address of the page if it is public;
  • the Console messages that start with [Ultimate Web View];
  • for engine problems on Windows and Linux, the file Logs/UltimateWebViewHost.log, written when Engine log level is Everything.

If the package is useful to you, a review on the Asset Store helps other developers find it. Thank you!

Changelog

1.1.0

  • Added – H.264, AAC and HEVC setting (Windows, Linux, off by default): switches to an engine build that plays MP4 files, HLS streams and known livestream sites. HEVC also plays on Windows when Hardware acceleration is on. Builds stay the same size; the package grows by 326 MB for Windows and 307 MB for Linux.
  • Added – DRM (Widevine) setting: the engine downloads the Widevine module when it starts. On desktop, protected audio plays; protected video plays its sound but its picture stays black. Known streaming movie sites refuse on Windows.
  • Added – inspector warning: Web View Screen and Web View Image warn when the address is a known livestream or video site that needs H.264, or an MP4 or HLS address, and the codecs are off. An Open Settings button opens the settings page.
  • Fixed – Linux DRM off: a Widevine module downloaded earlier is no longer loaded while DRM is off.
  • Docs: the documentation, store page and third-party notices now cover the patents and the new sizes.

1.0.0

First release.

  • WebView scripting API: navigation, pointer and keyboard input, JavaScript, messaging, cookies and stored data.
  • Display components: WebViewScreen for meshes, WebViewImage for uGUI, WebViewElement for UI Toolkit.
  • WebViewPointer with mouse, screen centre, transform and virtual cursor modes.
  • On-screen keyboard with QWERTY, AZERTY and QWERTZ layouts, in overlay and world modes.
  • Page sound through Unity audio on Windows and Linux, with WebViewAudio for 3D sound.
  • Engines: Chromium 156 for Windows x64, Linux x64 and the Editor on both, sandboxed on Windows; Android System WebView; WKWebView on iOS and, as a preview, on macOS; iframe overlay in WebGL.
  • Editor: Welcome window, Browser window, settings page, build steps for Windows, Linux, Android and iOS.
  • Four demo scenes for the Built-in pipeline, URP and HDRP.
Back to top