Qt For WebAssembly - Tips and Tricks

14 May 2026

Over the last couple of years, Qt For WebAssembly has proven that it is a mature platform to bring your native Qt C++ and QtQuick/QML applications to the web. With support for a variety of data backends (including REST services accessed via QNetworkAccessManager, and MQTT brokers accessed via QMqttClient), using Qt For WebAssembly your application which was originally built for desktop, mobile, or embedded can be built for the web and served to any device with a web browser.

We have one client which is heavily leveraging this capability to provide their customers with global access to their embedded devices via their application which is built both for native (embedded Linux) and WebAssembly (WASM) targets. We have worked extensively on this application, utilising Qt For WebAssembly, and leveraging the QtMQTT classes to access the sharded MQTT brokers via secure websockets. In this blog post, we will list some tips and tricks which are the product of our experiences throughout this project so far.

1) Design your UI with QtQuick/QML and utilise dynamic layouts

The variety of devices which will access your application via a web-browser is practically endless. Your application needs to support both portrait-mode (vertical) and landscape-mode (horizontal) layout, and support essentially arbitrary resolutions and aspect ratios. It should utilise QtQuick.Layouts to fill the available space intelligently, and use Flow elements where sensible to reflow content dynamically. To facilitate this, you should build your custom UI components with built-in support for different orientations. Where this is not feasible (due to complexity), it is permissible to implement separate components for portrait vs landscape uses, and load the appropriate component on-demand (using Loader or similar) depending on the current orientation. Each component should expose an appropriate implicit width and implicit height, so that layouts can correctly calculate the preferred geometry for each component within it; and then for instances which should expand if possible, specify `Layout.fillWidth` or `Layout.fillHeight` as appropriate.

2) Make use of animations and swipe gestures

Design your application to be as touch-friendly as possible. Even if your application was originally targeted at desktop platforms, you need to be conscious of the fact that web users require touch-flicking and panning, page swiping, and content animations. The performance of Qt For WebAssembly is exceptionally good, so for most applications, we recommend that you implement animations and full touch-gesture support. If your application was originally built for embedded touch screen displays, you should already have implemented these things - and luckily, they will all work without any changes when targeting the web!

3) Don't be afraid to modify the HTML loading page

You will almost certainly need to modify the HTML page which loads and displays the .wasm blob. For example: to set the visual viewport with a one-to-one mapping between CSS pixels and Qt device-independent pixels; or to style the HTML body to cover the entire visual viewport with no scrollbars; or to specify a watchdog to reload the wasm blob in case of a crash or abort. You should show an attractive loading progress bar while the .wasm blob is downloading, and you should make the entire view appear seamlessly. All of this requires touching the HTML which loads the blob.

4) Use emscripten APIs to interact with the HTML DOM

There may be cases where you should listen to events in the HTML DOM and react to them within your application. A common example is reacting to page visibility changes (you may wish to stop animations or other expensive things, in this case); another is to inspect the user-agent string to determine whether a high-quality native virtual keyboard is available by default; or to work around bugs in input handling (you can use tricks like selecting all input elements whose type is equal to "text" and set their visibility to hidden when you know that no text fields in your application have focus) - although it should be noted that in recent versions of Qt For WebAssembly, we have not encountered any such bugs any more.

5) Compress your .wasm blob with gzip

A large application which makes use of various Qt modules (such as QtQuick and QtMQTT) will become a large .wasm blob once compiled. You should compress this blob with gzip so that clients can load the application faster, and using less of your server's bandwidth. You may need to expose the size of this blob directly to the client as a separate resource, so that the loading progress bar can be calibrated correctly. You should bundle all resources that your application uses (fonts, images, etc) into Qt Resource Files (QRC) which are bundled into your executable, to avoid round-trip latency as much as possible.

6) Do not use any synchronous/blocking APIs

This is good advice for any application, but it is vital when you are targeting the web via Qt For WebAssembly. By default, Qt For WebAssembly is single-threaded (although as of recently, you can build with multithreaded support, our recommendation is to stick with single-threaded builds for now). This means that any blocking calls will freeze your UI and the entire tab. So, only make use of asynchronous, event driven APIs which do not synchronously block.

7) Use REST-over-https or MQTT-over-secure-websockets to access data backends

Use QNetworkAccessManager to access REST APIs for data, or QMqttClient to access MQTT brokers for data. Don't rely on LocalStorage, as clients may wish to access the application from different personal devices (phone vs tablet). Ensure you comply with all privacy and data storage laws when storing client data on your own infrastructure, and use secure defaults for how you access it (https for REST, wss for MQTT).

8) Disable link-time-optimisation for faster developer builds

When producing release builds, you should enable link-time-optimisation for your Qt For WebAssembly application, as this will have the best performance (which is very important when your code will be running on various different devices including potentially low-end mobile phones). It should be noted, however, that such builds can take a very long time (during the final link step). To avoid paying this cost during iterative development, you should turn LTO off for developer builds, and you can also disable various other optimisation options which can slow down builds.

In CMake, you can do this via:

# For faster builds. Don't enable this for release builds!

add_link_options("-O0" "-sWASM_BIGINT" "-sERROR_ON_WASM_CHANGES_AFTER_LINK")

set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF)

There we have it: some of our tips and tricks to keep in mind when leveraging Qt For WebAssembly to bring your desktop, mobile, or embedded application to the web. As always, if you would like some expert help using QtQuick/QML, or with Qt For WebAssembly, please get in touch via our email address or contact form.

Next
Next

Qt 6.5 LTS and Qt For WebAssembly