Skip to content

WebView

Usage

import toga

webview = toga.WebView()

# Request a URL be loaded in the webview.
webview.url = "https://beeware.org"

# Load a URL, and wait (non-blocking) for the page to complete loading
await webview.load_url("https://beeware.org")

# Load static HTML content into the wevbiew.
webview.set_content("https://example.com", "<html>...</html>")

System requirements

  • Using WebView on Windows 10 requires that your users have installed the Edge WebView2 Evergreen Runtime. This is installed by default on Windows 11.

  • Using WebView on Linux requires that the user has installed the system packages for WebKit2, plus the GObject Introspection bindings for WebKit2. The name of the system package required is distribution dependent:

    • Ubuntu 20.04; Debian 11: gir1.2-webkit2-4.0
    • Ubuntu 22.04+; Debian 12+: gir1.2-webkit2-4.1
    • Fedora: webkit2gtk4.1
    • Arch/Manjaro: webkit2gtk-4.1
    • OpenSUSE Tumbleweed: libwebkit2gtk3 typelib(WebKit2)
    • FreeBSD: webkit2-gtk3

    WebView is not fully supported on GTK4. If you want to contribute to the GTK4 WebView implementation, you will require v6.0 of the WebKit2 libraries. This is provided by gir1.2-webkit-6.0 on Ubuntu/Debian, and webkitgtk6.0 on Fedora; for other distributions, consult your distribution's platform documentation.

Notes

  • Due to app security restrictions, WebView can only display http:// and https:// URLs, not file:// URLs. To serve local file content, run a web server on localhost using a background thread.

  • On macOS 13.3 (Ventura) and later, the content inspector for your app can be opened by running Safari, enabling the developer tools, and selecting your app's window from the "Develop" menu. On macOS versions prior to Ventura, the content inspector is not enabled by default, and is only available when your code is packaged as a full macOS app (e.g., with Briefcase). To enable debugging, run: > console > $ defaults write com.example.appname WebKitDeveloperExtras -bool true > > > Substituting com.example.appname with the bundle ID for your > packaged app.

  • On Android, use of the on_navigation_starting or on_webview_load handler requires adding chaquopy.defaultConfig.staticProxy("toga_android.widgets.internal.webview") to the build_gradle_extra_content section of your app's pyproject.toml configuration. Loading large (>2MB) HTML content from a string requires the same configuration change, as well as the addition of "androidx.webkit:webkit:1.15.0" to the build_gradle_dependencies section.

Reference

Bases: Widget

Source code in core/src/toga/widgets/webview.py
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
class WebView(Widget):
    def __init__(
        self,
        id: str | None = None,
        style: StyleT | None = None,
        url: str | None = None,
        content: str | None = None,
        user_agent: str | None = None,
        on_navigation_starting: OnNavigationStartingHandler | None = None,
        on_webview_load: OnWebViewLoadHandler | None = None,
        **kwargs,
    ):
        """Create a new WebView widget.

        :param id: The ID for the widget.
        :param style: A style object. If no style is provided, a default style
            will be applied to the widget.
        :param url: The full URL to load in the WebView. If not provided,
            an empty page will be displayed.
        :param content: The HTML content to display in the WebView. If `content` is
            provided, the value of `url` will be used as the root URL for the content
            that is displayed; this URL will be used to resolve any relative URLs in the
            content. **Note:** On Android and Windows, if `content` is specified, any
            value provided for the `url` argument will be ignored.
        :param user_agent: The user agent to use for web requests. If not
            provided, the default user agent for the platform will be used.
        :param on_navigation_starting: A handler that will be invoked when the
            web view is requesting permission to navigate or redirect
            to a different URI.
        :param on_webview_load: A handler that will be invoked when the web view
            finishes loading.
        :param kwargs: Initial style properties.
        """
        super().__init__(id, style, **kwargs)

        self.user_agent = user_agent

        # Set the load handler before loading the first URL.
        self.on_webview_load = on_webview_load

        # Set the handler for URL filtering
        self.on_navigation_starting = on_navigation_starting

        # Load both content and root URL if it's provided by the user.
        # Otherwise, load the URL only.
        if content is not None:
            self.set_content(url, content)
        else:
            self.url = url

    def _create(self) -> Any:
        return self.factory.WebView(interface=self)

    def _set_url(self, url: str | None, future: asyncio.Future | None) -> None:
        # Utility method for validating and setting the URL with a future.
        if (url is not None) and not url.startswith(("https://", "http://")):
            raise ValueError("WebView can only display http:// and https:// URLs")

        self._impl.set_url(url, future=future)

    @property
    def url(self) -> str | None:
        """The current URL, or `None` if no URL is currently displayed.

        After setting this property, it is not guaranteed that reading the property will
        immediately return the new value. To be notified once the URL has finished
        loading, use [`load_url`][toga.WebView.load_url] or
        [`on_webview_load`][toga.WebView.on_webview_load].
        """
        return self._impl.get_url()

    @url.setter
    def url(self, value: str | None) -> None:
        self._set_url(value, future=None)

    async def load_url(self, url: str) -> asyncio.Future:
        """Load a URL, and wait until the next
        [`on_webview_load`][toga.WebView.on_webview_load] event.

        **Note:** On Android, this method will return immediately.

        :param url: The URL to load.
        """
        loop = asyncio.get_event_loop()
        loaded_future = loop.create_future()
        self._set_url(url, future=loaded_future)
        return await loaded_future

    @property
    def on_navigation_starting(self) -> OnNavigationStartingHandler:
        """A handler that will be invoked when the webview is requesting
        permission to navigate or redirect to a different URI.

        The handler will receive the requested URL as an argument. It should
        return `True` if navigation to the given URL is permitted, or `False`
        if navigation to the URL should be blocked.

        **Note:** This is not currently supported on GTK or Qt.
        """
        return self._on_navigation_starting

    @on_navigation_starting.setter
    def on_navigation_starting(self, handler):
        """Set the handler to invoke when the webview starts navigating."""
        if handler:
            if getattr(self._impl, "SUPPORTS_ON_NAVIGATION_STARTING", True):

                def cleanup(widget, result, url=None, **kwargs):
                    if result is True:
                        # navigate to the url
                        self.url = url

            else:
                cleanup = None
                try:
                    # Some backends (e.g., Android) will dynamically disable
                    # SUPPORTS_ON_NAVIGATION_STARTING based on configuration.
                    # If that happens, display an appropriate error; fall back
                    # to a simple "non implemented" otherwise.
                    print(self._impl.ON_NAVIGATION_CONFIG_MISSING_ERROR)
                except AttributeError:
                    self.factory.not_implemented("WebView.on_navigation_starting")
        else:
            cleanup = None

        self._on_navigation_starting = wrapped_handler(self, handler, cleanup=cleanup)

    @property
    def on_webview_load(self) -> OnWebViewLoadHandler:
        """The handler to invoke when the web view finishes loading.

        Rendering web content is a complex, multithreaded process. Although a page
        may have completed *loading*, there's no guarantee that the page has been
        fully *rendered*, or that the widget representation has been fully updated.
        The number of load events generated by a URL transition or content change can
        be unpredictable. An `on_webview_load` event should be interpreted as an
        indication that some change has occurred, not that a *specific* change has
        occurred, or that a specific change has been fully propagated into the
        rendered content.
        """
        return self._on_webview_load

    @on_webview_load.setter
    def on_webview_load(self, handler: OnWebViewLoadHandler) -> None:
        if handler and not getattr(self._impl, "SUPPORTS_ON_WEBVIEW_LOAD", True):
            try:
                # Some backends (e.g., Android) will dynamically disable
                # SUPPORTS_ON_WEBVIEW_LOAD based on configuration.
                # If that happens, display an appropriate error; fall back
                # to a simple "non implemented" otherwise.
                print(self._impl.ON_LOAD_CONFIG_MISSING_ERROR)
            except AttributeError:
                self.factory.not_implemented("WebView.on_webview_load")

        self._on_webview_load = wrapped_handler(self, handler)

    @property
    def user_agent(self) -> str:
        """The user agent to use for web requests.

        **Note:** On Windows, this property will return an empty string until the widget
        has finished initializing.
        """
        return self._impl.get_user_agent()

    @user_agent.setter
    def user_agent(self, value: str) -> None:
        self._impl.set_user_agent(value)

    def set_content(self, root_url: str, content: str) -> None:
        """Set the HTML content of the WebView.

        **Note:** On Android and Windows, the `root_url` argument is ignored. Calling
        this method will set the `url` property to `None`.

        :param root_url: A URL which will be returned by the `url` property,
            and used to resolve any relative URLs in the content.
        :param content: The HTML content for the WebView
        """
        self._impl.set_content(root_url, content)

    @property
    def content(self):
        """A write-only attribute to set the HTML content currently displayed by the
        WebView.

        `web_view.content = "<html>..."` is equivalent to calling
        `web_view.set_content("", "<html>...")`.

        :raises AttributeError: If an attempt is made to read the page content.
        """
        raise AttributeError("WebView.content is a write-only attribute")

    @content.setter
    def content(self, value):
        """Setter for content. Equivalent to the method set_content("", value)."""
        self.set_content("", value)

    @property
    def cookies(self) -> CookiesResult:
        """Retrieve cookies from the WebView.

        **This is an asynchronous property**. The value returned by this method must be
        awaited to obtain the cookies that are currently set.

        **Note:** This property is not currently supported on Android or Linux.

        :returns: An object that returns a CookieJar when awaited.
        """
        return self._impl.get_cookies()

    def evaluate_javascript(
        self,
        javascript: str,
        on_result: OnResultT | None = None,
    ) -> JavaScriptResult:
        """Evaluate a JavaScript expression.

        **This is an asynchronous method**. There is no guarantee that the JavaScript
        has finished evaluating when this method returns. The object returned by this
        method can be awaited to obtain the value of the expression.

        **Note:** On Android and Windows, *no exception handling is performed*. If a
        JavaScript error occurs, a return value of None will be reported, but no
        exception will be provided.

        :param javascript: The JavaScript expression to evaluate.
        :param on_result: **DEPRECATED** `await` the return value of this method.
        """
        return self._impl.evaluate_javascript(javascript, on_result=on_result)

content property writable

A write-only attribute to set the HTML content currently displayed by the WebView.

web_view.content = "<html>..." is equivalent to calling web_view.set_content("", "<html>...").

:raises AttributeError: If an attempt is made to read the page content.

cookies property

Retrieve cookies from the WebView.

This is an asynchronous property. The value returned by this method must be awaited to obtain the cookies that are currently set.

Note: This property is not currently supported on Android or Linux.

:returns: An object that returns a CookieJar when awaited.

on_navigation_starting property writable

A handler that will be invoked when the webview is requesting permission to navigate or redirect to a different URI.

The handler will receive the requested URL as an argument. It should return True if navigation to the given URL is permitted, or False if navigation to the URL should be blocked.

Note: This is not currently supported on GTK or Qt.

on_webview_load property writable

The handler to invoke when the web view finishes loading.

Rendering web content is a complex, multithreaded process. Although a page may have completed loading, there's no guarantee that the page has been fully rendered, or that the widget representation has been fully updated. The number of load events generated by a URL transition or content change can be unpredictable. An on_webview_load event should be interpreted as an indication that some change has occurred, not that a specific change has occurred, or that a specific change has been fully propagated into the rendered content.

url property writable

The current URL, or None if no URL is currently displayed.

After setting this property, it is not guaranteed that reading the property will immediately return the new value. To be notified once the URL has finished loading, use load_url or on_webview_load.

user_agent property writable

The user agent to use for web requests.

Note: On Windows, this property will return an empty string until the widget has finished initializing.

__init__(id=None, style=None, url=None, content=None, user_agent=None, on_navigation_starting=None, on_webview_load=None, **kwargs)

Create a new WebView widget.

:param id: The ID for the widget. :param style: A style object. If no style is provided, a default style will be applied to the widget. :param url: The full URL to load in the WebView. If not provided, an empty page will be displayed. :param content: The HTML content to display in the WebView. If content is provided, the value of url will be used as the root URL for the content that is displayed; this URL will be used to resolve any relative URLs in the content. Note: On Android and Windows, if content is specified, any value provided for the url argument will be ignored. :param user_agent: The user agent to use for web requests. If not provided, the default user agent for the platform will be used. :param on_navigation_starting: A handler that will be invoked when the web view is requesting permission to navigate or redirect to a different URI. :param on_webview_load: A handler that will be invoked when the web view finishes loading. :param kwargs: Initial style properties.

Source code in core/src/toga/widgets/webview.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
def __init__(
    self,
    id: str | None = None,
    style: StyleT | None = None,
    url: str | None = None,
    content: str | None = None,
    user_agent: str | None = None,
    on_navigation_starting: OnNavigationStartingHandler | None = None,
    on_webview_load: OnWebViewLoadHandler | None = None,
    **kwargs,
):
    """Create a new WebView widget.

    :param id: The ID for the widget.
    :param style: A style object. If no style is provided, a default style
        will be applied to the widget.
    :param url: The full URL to load in the WebView. If not provided,
        an empty page will be displayed.
    :param content: The HTML content to display in the WebView. If `content` is
        provided, the value of `url` will be used as the root URL for the content
        that is displayed; this URL will be used to resolve any relative URLs in the
        content. **Note:** On Android and Windows, if `content` is specified, any
        value provided for the `url` argument will be ignored.
    :param user_agent: The user agent to use for web requests. If not
        provided, the default user agent for the platform will be used.
    :param on_navigation_starting: A handler that will be invoked when the
        web view is requesting permission to navigate or redirect
        to a different URI.
    :param on_webview_load: A handler that will be invoked when the web view
        finishes loading.
    :param kwargs: Initial style properties.
    """
    super().__init__(id, style, **kwargs)

    self.user_agent = user_agent

    # Set the load handler before loading the first URL.
    self.on_webview_load = on_webview_load

    # Set the handler for URL filtering
    self.on_navigation_starting = on_navigation_starting

    # Load both content and root URL if it's provided by the user.
    # Otherwise, load the URL only.
    if content is not None:
        self.set_content(url, content)
    else:
        self.url = url

evaluate_javascript(javascript, on_result=None)

Evaluate a JavaScript expression.

This is an asynchronous method. There is no guarantee that the JavaScript has finished evaluating when this method returns. The object returned by this method can be awaited to obtain the value of the expression.

Note: On Android and Windows, no exception handling is performed. If a JavaScript error occurs, a return value of None will be reported, but no exception will be provided.

:param javascript: The JavaScript expression to evaluate. :param on_result: DEPRECATED await the return value of this method.

Source code in core/src/toga/widgets/webview.py
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
def evaluate_javascript(
    self,
    javascript: str,
    on_result: OnResultT | None = None,
) -> JavaScriptResult:
    """Evaluate a JavaScript expression.

    **This is an asynchronous method**. There is no guarantee that the JavaScript
    has finished evaluating when this method returns. The object returned by this
    method can be awaited to obtain the value of the expression.

    **Note:** On Android and Windows, *no exception handling is performed*. If a
    JavaScript error occurs, a return value of None will be reported, but no
    exception will be provided.

    :param javascript: The JavaScript expression to evaluate.
    :param on_result: **DEPRECATED** `await` the return value of this method.
    """
    return self._impl.evaluate_javascript(javascript, on_result=on_result)

load_url(url) async

Load a URL, and wait until the next on_webview_load event.

Note: On Android, this method will return immediately.

:param url: The URL to load.

Source code in core/src/toga/widgets/webview.py
115
116
117
118
119
120
121
122
123
124
125
126
async def load_url(self, url: str) -> asyncio.Future:
    """Load a URL, and wait until the next
    [`on_webview_load`][toga.WebView.on_webview_load] event.

    **Note:** On Android, this method will return immediately.

    :param url: The URL to load.
    """
    loop = asyncio.get_event_loop()
    loaded_future = loop.create_future()
    self._set_url(url, future=loaded_future)
    return await loaded_future

set_content(root_url, content)

Set the HTML content of the WebView.

Note: On Android and Windows, the root_url argument is ignored. Calling this method will set the url property to None.

:param root_url: A URL which will be returned by the url property, and used to resolve any relative URLs in the content. :param content: The HTML content for the WebView

Source code in core/src/toga/widgets/webview.py
209
210
211
212
213
214
215
216
217
218
219
def set_content(self, root_url: str, content: str) -> None:
    """Set the HTML content of the WebView.

    **Note:** On Android and Windows, the `root_url` argument is ignored. Calling
    this method will set the `url` property to `None`.

    :param root_url: A URL which will be returned by the `url` property,
        and used to resolve any relative URLs in the content.
    :param content: The HTML content for the WebView
    """
    self._impl.set_content(root_url, content)

Bases: Protocol

Source code in core/src/toga/widgets/webview.py
19
20
21
22
23
24
25
class OnWebViewLoadHandler(Protocol):
    def __call__(self, widget: WebView, **kwargs: Any) -> None:
        """A handler to invoke when the WebView is loaded.

        :param widget: The WebView that was loaded.
        :param kwargs: Ensures compatibility with arguments added in future versions.
        """

__call__(widget, **kwargs)

A handler to invoke when the WebView is loaded.

:param widget: The WebView that was loaded. :param kwargs: Ensures compatibility with arguments added in future versions.

Source code in core/src/toga/widgets/webview.py
20
21
22
23
24
25
def __call__(self, widget: WebView, **kwargs: Any) -> None:
    """A handler to invoke when the WebView is loaded.

    :param widget: The WebView that was loaded.
    :param kwargs: Ensures compatibility with arguments added in future versions.
    """

Bases: Protocol

Source code in core/src/toga/widgets/webview.py
28
29
30
31
32
33
34
35
36
37
class OnNavigationStartingHandler(Protocol):
    def __call__(self, widget: WebView, url: str, **kwargs: Any) -> bool:
        """A handler to invoke when the WebView is requesting permission to navigate or
        redirect to a different URI.

        :param widget: The WebView that has requested a new URI.
        :param url: The URI that has been requested.
        :param kwargs: Ensures compatibility with arguments added in future versions.
        :returns: True if navigation to the requested URL is allowed; False otherwise.
        """

__call__(widget, url, **kwargs)

A handler to invoke when the WebView is requesting permission to navigate or redirect to a different URI.

:param widget: The WebView that has requested a new URI. :param url: The URI that has been requested. :param kwargs: Ensures compatibility with arguments added in future versions. :returns: True if navigation to the requested URL is allowed; False otherwise.

Source code in core/src/toga/widgets/webview.py
29
30
31
32
33
34
35
36
37
def __call__(self, widget: WebView, url: str, **kwargs: Any) -> bool:
    """A handler to invoke when the WebView is requesting permission to navigate or
    redirect to a different URI.

    :param widget: The WebView that has requested a new URI.
    :param url: The URI that has been requested.
    :param kwargs: Ensures compatibility with arguments added in future versions.
    :returns: True if navigation to the requested URL is allowed; False otherwise.
    """