Planet Igalia WebKit

June 08, 2026

Igalia WebKit Team

WebKit Igalia Periodical #67

Update on what happened in WebKit in the week from June 1 to June 8.

Another great week, this time we have a performance improvement implemented in the Skia-based compositor, an excellent writeup about how to investigate and isolate memory leaks in WPE WebKit, a couple of multimedia fixes, and a variety of improvements and fixes across WebKit ports.

Cross-Port 🐱

Implement dialog integration with close watcher.

Implement node iterator and live range pre-remove steps for in-progress moveBefore() implementation.

Fix an early return in CloseWatcher close to align with the spec.

The Web Inspector now shows DOM nodes associated with layout and rendering events in a separate column of layout timeline next to initiator, sizing, and timing information. Hovering over rows in the details table highlights the associated node, and clicking it reveals the node in the "Elements" tab. This makes it easier to match events with specific nodes and helps debugging changes to a web page.

Fix popover light dismiss to account for disabled command buttons.

Multimedia 🎥

GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.

Fix mediaTime provided with requestVideoFrameCallback in case of captureCanvas as source.

Graphics 🖼️

Batched painting support was implemented in the Skia-based compositor, improving the performance in several cases.

Community & Events 🤝

Pawel Lampe published a blog post where he's presenting and discussing a guide on structured approach to narrowing down and debugging memory leaks within WPE WebKit.

That’s all for this week!

by Igalia WebKit Team at June 08, 2026 08:57 PM

June 02, 2026

Igalia WebKit Team

WebKit Igalia Periodical #66

Update on what happened in WebKit in the week from May 19 to June 1.

The main feature of this week are new releases: stable ones with many security fixes, and development ones with the new Skia-based compositor enabled. Additionally, there was work on Web-facing features, optimizations, spell checking support for the WPE port, and more.

Cross-Port 🐱

WebKit now supports mirroring MathML stretchy operators using the OpenType rtlm feature.

Replaced the CloseWatcherManager's escapeKeyHandler, which will allow other types of close signals to be supported.

Implemented queuing mutation observer records in the work-in-progress moveBefore() implementation.

Implemented popover integration with close watcher.

Fixed popover light dismiss to account for popovertarget on input buttons.

Content filters now create temporary files in the compiled filters directory, which ensures that a file rename can always be used to place them at their final location. This avoids falling back to a regular file copy, which can be slower, when the temporary directory returned by g_get_tmp_dir() (typically /tmp) is in a different volume than the filters' storage path configured for WebKitUserContentFilterStore.

WPE WebKit 📟

Enabled spell checking support in WPE. The existing implementation for the WebKitGTK port, which uses the Enchant library as a backend, was generalized to provide spell checking support in WPE as well. The feature may be toggled at build time using the ENABLE_SPELLCHECK CMake option.

Releases 📦️

WebKitGTK 2.52.4 and WPE WebKit 2.52.4 have been released; they include a number of fixes for security issues, and it is a highly recommended update. The corresponding security advisory, WSA-2026-0003 (GTK, WPE is available as well. The release also includes a number of small improvements and Web compatibility fixes.

Additionally, development releases WebKitGTK 2.53.3 and WPE WebKit 2.53.3 are available since last week. These include a change to use a new Skia-based compositor by default, which is intended to replace TextureMapper once ready. Therefore, bug reports related to website rendering are particularly welcome when using this and subsequent development releases.

Infrastructure 🏗️

The deprecated and un-maintained Flatpak-based SDK was removed. Developers working on the WPE and GTK WebKit ports are encouraged to migrate to the new SDK.

That’s all for this week!

by Igalia WebKit Team at June 02, 2026 12:12 AM

Pawel Lampe

WPE memory leak investigation playbook

Depending on the web application, the WPE WebKit memory usage trend can vary. When simple web applications are being processed, the memory consumption tends to be virtually stable (the same) no matter the period. However, when more complicated web applications are being executed, the memory usage usually grows over time while going back to normal from time to time e.g., when GC / memory pressure mechanism releases all kinds of caches and not-needed memory. Therefore, memory growth itself is not unusual. Nevertheless, as the memory leaks happen in WPE at times, the memory growth is worth investigating — especially if very rapid or unbounded.

This article presents a structured playbook for investigating such a memory growth and memory leaks in WPE. Rather than diving straight into debugging tools, it starts from first principles: confirming the problem is real, choosing the right environment to work in, and narrowing down the leaking area before any heavy tooling is involved. The goal is to reach actual debugging as fast as possible, regardless of whether the environment is an embedded device or a desktop machine, and regardless of how quickly the problem reproduces.

Playbook #

The high-level list of recommended steps to follow is presented below. In a nutshell, the steps 1, 2, and 3 are meant to choose and follow the fastest possible investigation path so that actual debugging of the problem (step 4) can be started as soon as possible.

  1. Confirming the problem
  2. Identifying the best setup for reproducing the problem
  3. Narrowing down
  4. Debugging

1. Confirming the problem #

The ultimate first step when working with alleged memory leak is to check whether the observed memory growth is actually abnormal. In the case of web browsers in general, the memory growth alone may not necessarily mean something is leaking. There may be many regular reasons why the browser’s memory usage is growing, but the usual suspects are:

  • JavaScript-level memory allocations — due to the very nature of JavaScript, the memory it allocates causes the overall web content process memory growth up until the garbage collector (GC) kicks in. Then (from the RSS perspective) some memory is usually freed. However, as it’s not easy to predict when the GC will be invoked (e.g., when the browser processes an application that performs heavy rendering), it’s possible that memory will grow but remain garbage-collectible.
  • JavaScript Just-in-Time (JIT) compilation — when not explicitly disabled or limited, the processing of any web application that has JavaScript code associated with it will cause the browser to continuously compile the JavaScript code in the background so that it executes such code faster in runtime at the expense of memory that is required for storing compiled artifacts.
  • Caches — as the WPE operates, it caches things such as web resources, style resolution artifacts, textures, glyph atlases, layer tiles, display lists, rasterization artifacts, and many others. Naturally, the cache sizes are limited, however, if many caches are growing at the same time, they may create an impression of a leak. The difference in that case is, the caches stop growing at some point.

Due to the above, to confirm the memory growth is abnormal, one should usually try the following first:

  1. Triggering memory pressure to force the browser to trigger GC and evict as many cache entries as possible,
  2. Rerunning the browser with JIT disabled to rule out the JIT-related memory growth — unless the application code is very small.

If the memory growth doesn’t stop with JIT disabled or its level does not go back to normal after triggering memory pressure, the growth can be assumed to be abnormal, and one can proceed to the next step.

2. Identifying the best setup for reproducing the problem #

When the memory growth is atypical, it needs to be narrowed down in a way that the final debugging is possible. For both narrowing down and the debugging, one should aim at the most flexible development environment along with the smallest possible web application that reproduces the problem quickly. What it means in practice is — desktop environment along with small demo web application that reproduces the problem. Whilst it’s not always possible to have such an environment, the 3 general rules are as follows:

  1. Desktop environment is usually better than embedded one in terms of working with memory leaks as it offers minimal overhead (e.g., in terms of compilation times) and huge flexibility in choosing the industry standard tools for profiling/debugging.
  2. Small web application is always better than a big one as long as it still reproduces the same problem in the same amount of time. In such case, a small application minimizes the amount of noise that usually stands in the way of profiling/debugging.
  3. A web application that reproduces the problem quickly is always better than the one that needs much more time for it. The worst thing that can happen in the case of narrowing down memory leaks, is when the memory growth is noticeable or starts after a very long time such as hours/days+.

Given the above, at this point one should go through the below steps:

  1. Check if the setup is trivial enough already — if the web application reproduces the problem quickly in a desktop environment and is simple enough, one should immediately jump to the Debugging section.
  2. Check if the problem can be reproduced on desktop assuming it originally reproduces on embedded.
  3. Check if the problem can be reproduced faster if it’s not reproducing fast enough.
  4. Check if the web application could be simplified.

Once the setup is simplified as much as possible, one should proceed to one of narrowing down sections depending on the setup. Also, if the setup is still not ideal, one should actively seek opportunities for simplifying the setup even during narrowing down as it’s likely that some new information will eventually open new possibilities in terms of simplifying setup.

3. Narrowing down #

When the problem has been confirmed but there are not enough clues to tell exactly which parts leak, the debugging cannot be started right away. In such case, it’s necessary to narrow down the problem to the browser/application area that can be easily debugged.

While in some cases narrowing down is not even necessary, quite often it takes orders of magnitude more time than actual debugging, and hence one should pay special attention to this step.

3a. Narrowing down on embedded when the problem takes a long time to reproduce #

This is the toughest situation one can find themselves in. When a problem takes a long time to reproduce (hours/days+), every iteration/test comes automatically with a significant cost. Moreover, when the environment is an embedded one, rebuilding WPE is usually more time-consuming and the amount of tooling is usually limited — or requires some work to bring it to the image at least.

Due to the above, narrowing down the problem in this setup requires a structured approach with extra care. In such case, the things to check should be approached in steps defined as follows:

  1. Things to check without rerunning the WebKit
    • in case of embedded devices, extra care is needed when attaching a memory profiler. On low-end devices, memory profilers tend to slow down the application hard enough to trigger otherwise non-existent problems.
  2. Things to check without rebuilding the WebKit
    • in case of embedded devices, one should prefer limiting JIT over disabling it as without it, the JS execution may be slow enough to trigger unexpected scenarios.
  3. Things to check if rebuilding WebKit

Ideally, while checking various things along the above steps, one should batch as many checks as possible within individual tests.

3b. Narrowing down on embedded when the problem reproduces quickly #

When the problem reproduces quickly, the limitations of embedded environment are not that relevant. In this scenario, one should prioritize getting debug symbols (RelWithDebInfo build) into the image and utilizing them by running the browser with whatever profilers are available. For the specific things to check, one should seek inspiration in the following groups:

  1. Things to check without rebuilding the WebKit.
  2. Things to check if rebuilding WebKit.

3c. Narrowing down on desktop when the problem takes a long time to reproduce #

This situation is similar to 3a and hence one should follow the things to check from the following groups:

  1. Things to check without rerunning the WebKit.
  2. Things to check without rebuilding the WebKit.
  3. Things to check if rebuilding WebKit.

However, this time, there are some extra opportunities around tooling:

  1. There should be many more tools available already in the system or available to be installed.
  2. Tools such as memory profilers that could slow down the application making it unusable on embedded, may turn out to be working well when the desktop-class processing power is available.

With the above in mind, it’s worth trying all the tools available with priority because if at least one tool works well, one can save hours of narrowing down.

3d. Narrowing down on desktop when the problem reproduces quickly #

This is technically the simplest possible scenario, so basically, all the possibilities are available. The most time-consuming activity in this case is very likely rebuilding WebKit itself — although it should still be relatively fast. In such case, just after a few quick checks with the Web Inspector, it’s recommended to get debug symbols (RelWithDebInfo build) and start with tools such as memory profilers.

Other than the above, one should go through the following groups on things to check:

  1. Things to check without rebuilding the WebKit.
  2. Things to check if rebuilding WebKit.

4. Debugging #

The WPE debugging is twofold and depends on whether the problem is within the engine (usually C/C++ code) or the web application (JavaScript code).

When problem lies in the engine #

Debugging WPE WebKit is the same as debugging any other C/C++ application on Linux (or Mac if the issue is cross-port and one prefers an Apple port to work with), and hence is outside the scope of this article. Some WebKit-specific information can be found in the WebKit Documentation article on building and debugging page and therefore is recommended as a first step.

When problem lies in web application #

When the problem lies in JavaScript code, the situation is usually fairly straightforward. The majority of bugs in this area should be reproducible across various browser engines and hence a full variety of tooling should be available. If the WebKit is preferred or if the problem reproduces only there, the tooling available is still very useful and helps debugging problems quickly. The ultimate tool in such case is the Web Inspector. On official WebKit’s web page there’s entire index of articles on Web Inspector. Among those, the most interesting read is about Timelines Tab where the most useful debugging can be done. Once the features of Timelines Tab are understood, the next important article is the memory debugging guide. It dives into the most important Timelines Tab subsections and showcases the work with heap snapshots which is a key. To supplement it, it’s very important to know the heap snapshot delta feature which is basically about button:

Web Inspector heap delta.

that allows one to inspect the delta-snapshot between 2 snapshots. It’s critical as it answers the question on what JS objects were added between the base snapshot and the later one. If some objects are piling up, it immediately shows which ones.

One important note on snapshots is that in some cases when using Web Inspector is not possible, one can generate the snapshots manually from the web engine’s C++ code by just calling GarbageCollectionController::singleton().dumpHeap(); at some appropriate moment. In this case, the dump will be written to standard output. It can be then turned into a file and imported from any Web Inspector using Import button.

As the Timelines Tab with its subsections should be able to answer on what happens, to understand why it actually happens, the last missing piece is the JS debugger within Web Inspector. It’s not very different to debuggers in other engines, but it’s worth checking a dedicated article on it just to understand the capabilities.

Appendix #

Things to check without rerunning the webkit #

Even if the WPE is running with default settings in release mode, there are plenty of useful things that can be checked while the browser is still running:

  1. Identifying which WebKit process allocates abnormally,
    • there are multiple ways to do this, but usually it’s as easy as using ps utility.
  2. Identifying how fast the process in question allocates the memory,
    • this is useful to know at least for comparison purposes, but it may hint some problems already if the numbers correlate with what web application does.
  3. Checking logs from stdout, stderr, and journal (using journalctl).
  4. Checking detailed process memory statistics.
  5. Triggering and checking the impact of memory pressure on given processes RSS,
    • in short, memory pressure triggers the cleanup of the majority of caches along with GC. Therefore, if this is able to bring memory back to normal level, then the problem is about caches, JS Heap / GC, or fragmentation.
  6. Attaching memory profilers if available,
    • even if the debug symbols are not present, this may be useful to see what data is being captured and how the web application behaves when slowed down by profiler.
  7. Attaching other tools if available,
    • even if the debug symbols are not present, various tools offer different perspectives on what the browser is doing. In some cases, such information may reveal some anomalies that may be related to the main issue.
  8. Cross-checking with other browsers,
    • if other browsers show a similar pattern of memory usage, it’s very likely the problem lies in web application itself. Otherwise, it strongly suggests a bug in the WPE.
  9. Cross-checking with other ports,
    • if any other WebKit port shows a similar pattern of memory usage, it allows one to narrow down the area in the code a bit based on what port it is:
      • if the same behavior is visible in any of Apple ports, the problem is most likely related to cross-platform code,
      • if the same behavior is visible only in GTK port, then the problem is most likely related to GLib-related part, coordinated graphics part, GStreamer-related part, or others that are shared.

Things to check without rebuilding the webkit #

  1. Tweaking and checking the logs from WPE,
    • while generic logs may hint some unusual behavior, more specific ones such as GC logs (JSC_logGC=1) may be used to check how the individual JS heap sizes evolve over time and how GC behaves. If it’s JavaScript leaking the memory, this log will quickly provide the evidence.
  2. Enabling Remote Web Inspector and checking:
    • both breakdown and trend of memory usage in the memory timeline after doing a bit of recording,
    • the effects of takeHeapSnapshot() invoked from JS console:
      • as this function usually triggers GC internally, it may be used to check how much RSS memory is reclaimed by GC in isolation (followed up by scavenger),
      • as this function takes a JS heap snapshot, it then can be used to explore manually if its contents point towards something interesting.
  3. Disabling JIT and checking the memory usage,
    • if the memory usage is stable with JIT disabled, one should proceed to the step below.
  4. Limiting JIT and checking the memory usage,
    • there are at least a few places (levels) where JIT compilation engine allocates memory. If limiting doesn’t resolve the issue completely, it’s likely the engine itself leaks some memory around temporary helper-heaps such as AssemblerData etc.
  5. Experimenting with environment variables and runtime preferences,
    • some environment variables and runtime preferences change the behavior of the web engine significantly. If changing one of them makes the problem go away, it usually helps to narrow down the problematic area quickly.
  6. Running WPE with system malloc (environment variable Malloc=1) and checking the memory usage,
    • when one suspects bmalloc/libpas issues with fragmentation or scavenger, it’s worth running a browser with system malloc to compare the memory evolution over time against the bmalloc/libpas.
  7. Limiting device memory and checking the memory usage,
    • if triggering memory pressure is not possible, an alternative solution is to limit the device memory so that the browser is under constant memory pressure.
  8. Running WPE with sysprof and checking:
    • stack traces — to see what parts of engine are particularly active as it may hint some problematic area,
    • WebKit marks — to see what the engine is doing as well as quantitative data in marks such as EventLoopRun etc. as in those cases the numeric value trends may reveal resource pile up.

Things to check if rebuilding webkit #

  1. Building WPE in release mode with debug symbols and re-trying memory profilers or other tools if the debug symbols were not present before,
    • if some desired tools such as heaptrack, valgrind, perf, or strace were not available before, it’s the right moment to get/build them as well,
    • once the debug symbols are in, one should try:
  2. Building and running with Google perftools,
    • as WPE allows switching to system malloc as an allocator, it’s possible to use custom malloc implementation with instrumentation such as gperftools. For that, the recommended read is this article from fellow Igalian, Pablo Saavedra.
  3. Building and running with sanitizers,
    • if the problem is about low-level leak, address/leak sanitizer should be able to help pointing out the problematic area.
  4. Building and running with memory sampler,
    • the data produced by memory sampler is roughly the same as inspector’s memory timeline, however, it’s much more convenient as it doesn’t need web inspector at all.
  5. Building and running with node statistics,
    • when memory growth seems to be related to DOM mutations, it’s worth enabling and reporting node statistics periodically — in some cases, it may directly suggest what the problem is about.
  6. Building and running with malloc heap breakdown,
    • when all other means fail, a very good last-resort approach for investigating memory usage statistics via a debug-only WebKit feature called Malloc Heap Breakdown. The details can be found in the dedicated article about it.
  7. Building and running with libpas statistics,
    • On very rare occasions such as memory fragmentation or allocation issues, it may be worth checking the libpas (low-level memory allocation and management library) statistics as WPE uses it by default on the vast majority of platforms.

Individual instructions #

Checking detailed process memory statistics #

As WPE WebKit uses multi-process architecture, there are multiple processes that can be checked, although the most interesting one is usually the Web Content Process. Once the PID of the given process is determined (e.g., using ps utility) the usual steps to check detailed memory statistics are:

  • cat /proc/<PID>/status or cat /proc/<PID>/statm for very basic statistics,
  • pmap -X <PID> - for detailed statistics (if available),
  • cat /proc/<PID>/smaps_rollup and cat /proc/<PID>/smaps for detailed statistics (requires CONFIG_PROC_PAGE_MONITOR kernel configuration option).

Triggering memory pressure from OS #

WPE uses a so-called Memory Pressure Monitor to observe the memory usage in the system and to react if there’s not much memory left. The default thresholds are specified in MemoryPressureMonitor.cpp and usually are 90% for non-critical and 95% for critical response. Depending on the response, WPE schedules GC and clears internal caches immediately.

As the above is usually on by default, one can leverage it to trigger GC (along with cache cleanups) by filling up the available memory in the OS to 95+%. There are many ways to allocate memory, yet the simplest is using stress:

  • e.g. stress --vm 1 --vm-bytes 1024M --vm-keep to allocate 1024 MB.

Attaching memory profilers #

When attaching any memory profiler, unless one wants to profile only native allocations (Skia, GStreamer, ICU, etc.), the key is to use Malloc=1 environment variable on WPE startup so that bmalloc uses system malloc instead of libpas. Then the commands are as follows:

  • to attach heaptrack:
    • heaptrack -p <PID> so e.g. heaptrack -p $(pgrep WPEWebProcess) (see this article for details),
  • to run with valgrind’s massif (as attaching to running process is not possible):
    • valgrind --tool=massif --trace-children=yes <WPE-BROWSER-COMMAND> (see this article for details).

Attaching other tools #

If memory profilers are unusable or unavailable, it’s worth checking if other tools are present and experimenting a bit with them if so. In some cases, tools other than memory profilers may give some hints on further investigation or reveal a suspicious pattern within application execution. Some ideas for experiments with various tools are listed below:

  • strace:
    • strace -c -p $(pgrep WPEWebProcess)strace called with -c gives a nice summary of system calls executed by the traced application. It can be useful to check the overall syscall usage pattern to see if there are any anomalies.
    • strace -p $(pgrep WPEWebProcess) -e trace=mmap,munmap,mremap,madvise -ttstrace focused on mmap()-related system calls may be useful to debug libpas.
  • perf:
    • perf record -F 999 -ag -p $(pgrep WPEWebProcess) -- sleep 60 — regular recording with perf can be very useful, especially if symbols are available. With that, one can generate flamegraphs and investigate what’s going on in the browser. While it’s not about profiling memory, it may be helpful to narrow down at least a bit.
    • perf record -F 999 -e syscalls:sys_enter_mmap,syscalls:sys_enter_munmap,syscalls:sys_enter_mremap:sys_enter_madvise -ag -p $(pgrep WPEWebProcess) -- sleep 60perf focused on mmap()-related system calls is much more superior than e.g. strace as it also records stack traces. Therefore, if debug symbols are present, and if the memory growth is very rapid, it’s very likely the libpas mmap() stacktraces will lead to the growth origin statistically.
    • perf trace -e mmap,munmap,mremap,madvise -p $(pgrep WPEWebProcess) — this is very much similar to strace focused on mmap()-related system calls as it shows a live preview of what’s happening.
  • sysprof:
    • sysprof-cli -f — while running system-wide sysprof won’t make WPE push marks into it, the profiling trace may still be useful to some degree, especially if debug symbols are available.

Disabling JIT #

This can be done using an environment variable:

  • JSC_useJIT=false.

Limiting JIT #

Limiting JIT can be achieved via environment variables:

  • JSC_jitMemoryReservationSize=<BYTES> to limit JIT memory usage (the limit is semi-strict as some JIT compilation engine buffers are limited by this value indirectly),
  • JSC_useFTLJIT=false to disable FTL tier,
  • JSC_useDFGJIT=false to disable DFG and FTL tiers,
  • JSC_useBaselineJIT=false to disable Baseline, DFG, and FTL tiers.

Tweaking WPE logs #

WPE is a fairly complex piece of software and hence it offers various logging capabilities related to WebKit itself, as well as to related libraries. The vast majority of logging can be controlled via environment variables:

  • WEBKIT_DEBUG=all to enable all logging channels,
  • WEBKIT_DEBUG=Layout,Media=debug,Events=debug to enable selected logging channels,
  • JSC_logGC=2 to enable JS garbage collector logs,
  • GST_DEBUG=4 to enable gstreamer (multimedia-related) logs (see the documentation),
  • G_MESSAGES_DEBUG=all to enable GLib-level logs.

If MiniBrowser (or similar browser) is used, one can also set a runtime preference to enable JS console.log(...) logging to the standard output:

  • --features=+LogsPageMessagesToSystemConsole.

Enabling remote web inspector #

Enabling WPE’s remote web inspector is a twofold process:

  1. The first step is to run WPE with the proper environment variable so that it starts listening on IP:PORT using tcp socket:
  • WEBKIT_INSPECTOR_SERVER=IP:PORT is the most reasonable option as it uses inspector:// protocol that can be utilized by WebKit-native browsers such as GNOME Web (Epiphany) or Safari,
  • WEBKIT_INSPECTOR_HTTP_SERVER=IP:PORT is a less preferable alternative that uses HTTP protocol and technically works from any browser. However, no seamless integration is guaranteed in this case.
  1. The second step is to connect from a regular web browser to the WPE:
  • using inspector://IP:PORT/ if native inspector server was started,
  • using http://IP:PORT/ if HTTP inspector server was started,
  • forwarding the ports using socat tcp-l:PORT,fork,reuseaddr tcp:IP:PORT if the WPE is running in unreachable network.

Experimenting with environment variables and runtime preferences #

The most outstanding environment variables changing the behavior of WPE are the following:

  • WPE_DISPLAY — assuming the new WPE platform API is used, this environment variable allows one to switch the pre-defined platform implementation thus changing a platform-facing part of graphics pipeline. The valid options are:
    • WPE_DISPLAY=wpe-display-headless — for headless implementation,
    • WPE_DISPLAY=wpe-display-drm — for direct rendering manager integration,
    • WPE_DISPLAY=wpe-display-wayland — for wayland integration,
  • WEBKIT_SKIA_ENABLE_CPU_RENDERING — when set to 1, rendering the DOM contents to the layers is done using Skia CPU backend instead of GPU one.

The most outstanding runtime preferences changing the behavior of WPE are the following:

  • CanvasUsesAcceleratedDrawing — when disabled, 2D canvas will use Skia CPU backend instead of GPU one,
  • LayerBasedSVGEngine — when enabled, WPE uses a different SVG engine internally,
  • AcceleratedCompositing — when disabled, WPE uses experimental, non-composited mode that bypasses all of the compositor work.

Limiting device memory #

On the majority of embedded devices, the device memory can be limited by:

  1. Interrupting the boot sequence (usually holding some key such as z upon booting),
  2. Invoking the command to change the limit and booting, e.g.:
    > global linux.bootargs.console="console=ttymxc0,115200n8 mem=2G"
    > boot
    

Running WPE with sysprof #

Regardless of whether it’s done on desktop (using wkdev-sdk) or on embedded device, the command is always as simple as:

  • sysprof-cli -f -- <WPE-INVOCATION>.

See the documentation entry for more details.

Building WPE in release mode with debug symbols #

On desktop, the simplest way to get release with debug symbols is to utilize CMake’s build type by using -DCMAKE_BUILD_TYPE=RelWithDebInfo within WPE build command, so:

  • ./Tools/Scripts/build-webkit --wpe --release --cmakeargs="-DCMAKE_BUILD_TYPE=RelWithDebInfo".

On embedded, when Yocto is used, one should tweak settings such as:

IMAGE_GEN_DEBUGFS = "1"                                                         
IMAGE_FSTYPES_DEBUGFS = "tar.bz2"
DEBUG_BUILD = "1"
EXTRA_IMAGE_FEATURES_append = " dbg-pkgs"

and potentially INHIBIT_PACKAGE_STRIP to control whether debug symbols should be kept with the binary or not. This may be necessary occasionally as some tools have problems reading .gnu_debuglink and therefore work only with symbols included in the binaries.

Building and running with sanitizers #

WebKit works pretty well with all kinds of sanitizers. To build with any of them a CMake-level helper called ENABLE_SANITIZERS can be used by specifying -DENABLE_SANITIZERS=address, -DENABLE_SANITIZERS=leak etc. With that, the command for building e.g. on desktop could look like:

  • ./Tools/Scripts/build-webkit --wpe --debug --cmakeargs=-DENABLE_SANITIZERS=address.

For more details, one can refer to this article from fellow Igalian, Fujii.

Building and running with memory sampler #

When WPE is built with -DENABLE_MEMORY_SAMPLER=ON, the simple memory sampler can be started along with the browser using environment variable:

  • WEBKIT_SAMPLE_MEMORY=1.

With that, the memory of various WPE processes is sampled every second, and saved to the files under /tmp directory continuously.

Building and running with node statistics #

Node statistics are a debug-only feature that can be enabled by:

  • changing 0 of #define DUMP_NODE_STATISTICS 0 to 1 in Source/WebCore/dom/Element.h,
  • adding dumpStatistics() call, to e.g. Node constructor in Source/WebCore/dom/Node.cpp.

Building and running with libpas statistics #

Libpas statistics are a debug-only feature that can be enabled by changing 0 of #define PAS_ENABLE_STATS 0 to 1 in Source/bmalloc/libpas/src/libpas/pas_config.h and then running WPE with environment variable PAS_STATS_ENABLE=1.

June 02, 2026 12:00 AM

May 18, 2026

Igalia WebKit Team

WebKit Igalia Periodical #65

Update on what happened in WebKit in the week from May 11 to May 18.

For this week we have quite a collection of news! Ranging a variety of improvements to dialog.requestClose(), rendering fixes, the new Skia-based compositor enabled by default, and proper versioning and improvements to the WebKit Container SDK, there's news for everyone.

Cross-Port 🐱

Update the closeWatcher.requestClose() function to no longer require user activation, aligning with the spec.

Implement actually moving the node in the DOM when moveBefore() is called.

Fix handling of nested calls to dialog.requestClose().

Add missing preliminary checks to dialog.requestClose().

Graphics 🖼️

Fixed an issue where background images were unexpectedly stretched, primarily affecting the reCAPTCHA checkmark image.

The new compositor using Skia API instead of TextureMapper is now enabled by default.

Infrastructure 🏗️

Added opt-in auto-enter for the WebKit Container SDK - the GTK/WPE wrapper scripts (build-webkit, run-webkit-tests, run-api-tests, etc.) now relaunch themselves inside a pinned wkdev-build podman container when WEBKIT_CONTAINER_SDK_ENABLE_AUTOENTER=1 is set. A new .wkdev-sdk-version file at the repo root pins the SDK image, so the image can be bumped in a PR and validated through EWS. Without the flag, wrappers run on the host exactly as before.

Introduced a proper version scheme for the wkdev-sdk image provided by the WebKit Container SDK so consumers can pin to a known revision. The :latest tag, the WKDEV_SDK_TAG/--tag override and the tag/* branch mechanism are replaced by a single machine-checkable format <major>.<minor>-v<count>-<gitsha> (e.g. 2.53-v1-916f9ef), where <major>.<minor> tracks the WebKitGTK/WPE release cycle, v<count> is the per-cycle SDK build counter, and <gitsha> traces the image back to its source commit. wkdev-create gains a --version switch (full or bare <major>.<minor>). wkdev-update supports updating from latest tag to the new versioning scheme, just run it on your host to update to the latest SDK.

Switched the wkdev-build container from a persistent container to ephemeral podman run --rm --init per invocation. This removes the manual podman rm step necessary whenever container creation arguments changed (which the tooling was not handling by itself), the first-run recursive-chown cost, and the podman start step after host reboots.

That’s all for this week!

by Igalia WebKit Team at May 18, 2026 07:39 PM

May 11, 2026

Igalia WebKit Team

WebKit Igalia Periodical #64

Update on what happened in WebKit in the week from May 4 to May 11.

This week we have a bag of exciting updates, such as fixes to crashes, better YouTube playback, a handful of advancements to WebXR, and the development releases of WebKitGTK and WPE WebKit 2.53.2.

Cross-Port 🐱

If the filesystem runs out of space while the NetworkProcess is writing into its network cache, the process will crash with SIGBUS. This would surface to users as the "Internal error fired from WebLoaderStrategy.cpp(559) : internallyFailedLoadTimerFired" error, and would be handled by re-spawning another NetworkProcess that would similarly fail.

This was addressed by using fallocate, if available, to reserve the required size. If fallocate fails to reserve, the NetworkProcess will skip caching, avoiding the crash. If fallocate is not available, the existing behaviour is preserved.

Networking 📶

Networking support, including the libsoup HTTP library.

libsoup now supports the zstd compression encoding.

Multimedia 🎥

GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.

getUserMedia() and getDisplayMedia() support should work better thanks to a couple PipeWire related fixes.

Playback of some YouTube videos (usually at low framerate) has been fixed. Eventually a better solution will involve supporting edit lists in the GStreamer MSE backend.

Graphics 🖼️

A crash when accessing the diagnostics webkit://gpu page was fixed, making sure we handle the case where libGL.so.1 or libOpenGL.so.0 are missing.

Fixed missing glyph before ZWJ/ZWNJ if no font is found for the cluster.

The WebXR implementation based on OpenXR has gained support for quad, equirect and cylinder layers.

Releases 📦️

The second unstable releases for the current development cycle have been published: WebKitGTK 2.53.2 and WPE WebKit 2.53.2. Development releases are intended is to gather early feedback on upcoming changes, and as such issue reports are welcome in Bugzilla.

That’s all for this week!

by Igalia WebKit Team at May 11, 2026 08:04 PM

April 28, 2026

Igalia WebKit Team

WebKit Igalia Periodical #63

Update on what happened in WebKit in the week from April 8 to April 28.

After a short hiatus, we return with a galore of releases, more Web Platform improvements, tricky tweaks to thread scheduling, new niceties in the Web Inspector, and new build options to take advantage of compiler optimizations.

Cross-Port 🐱

Delivered a number of changes that have strengthened WPE WebKit and WebKitGTK's behaviour around real-time thread promotion and demotion:

  • Real-time soft and hard limits are now set both when sched_setscheduler or D-Bus based paths are taken (i.e. through rtkit or the corresponding XDG portal), with the soft limit set at 80% of the hard one.
  • This means WebKit now has time to gracefully handle SIGXCPU, and will do it in an async-signal-safe manner.
  • Additionally, the NetworkProcess' Cache Storage thread is now defined as QOS::UserInitiated on Linux, which no longer maps to real-time priority. Its earlier mapping to real-time was previously reported as a NetworkProcess crash in the logs (it was in practice a kernel-delivered SIGKILL, but WebKit doesn't make any distinction while logging). After limits were adjusted, this thread was successfully demoted, and now that the mapping has changed, this is no longer promoted to real-time to begin with.

Finally, logging around portal-related failures has been updated to reduce noise.

Implemented the connectedMoveCallback() for custom elements to react to moveBefore().

Implemented the scaffolding for the moveBefore() DOM function. This is the first step towards implementing the full feature and is currently behind a runtime feature flag.

The Web Inspector now highlights the layout root element by hovering over a Layout event in the “Layout & Rendering” timeline view and reveals it in the element tree by clicking a little “go to” arrow button.

Releases 📦️

WebKitGTK 2.52.2 and WPE WebKit 2.52.2 have been released, which include a number of fixes. In particular, building for some less tested configurations should now be possible, and the WPE port includes fixes for input event handling in the Qt API bindings.

The releases were quickly followed by WebKitGTK 2.52.3 and WPE WebKit 2.52.3, with further fixes including an important patch for crashes in JavaScriptCore on architectures other than x86_64, support for the scrollbar-color CSS property, and a fix for rendering certain emoji glyphs. Additionally, the WPE port also gained a new setting to disable overlay scroll bars and use always-visible ones, fixed focus handling for touch input in the built-in Wayland platform implementation, and a build fix for the Qt one.

In addition to maintenance for the stable branch, the first unstable releases for the current development cycle are also available: WebKitGTK 2.53.1 and WPE WebKit 2.53.1. These are the first published versions that remove the option to use Cairo for 2D rendering—only Skia will be supported going forward. On the additions front, there are graphics subsystem improvements, a few API additions, and initial support in the CMake build system for builds using Profile-Guided Optimization (PGO, needs Clang for now). The goal of development releases is to gather early feedback on upcoming changes, and issue reports are welcome in Bugzilla.

Infrastructure 🏗️

PGO (Profile-Guided Optimization) builds with Clang are now supported by the CMake build system.

That’s all for this week!

by Igalia WebKit Team at April 28, 2026 08:05 AM

April 07, 2026

Igalia WebKit Team

WebKit Igalia Periodical #62

Update on what happened in WebKit in the week from March 31 to April 7.

Support for iOS dialog light dismiss, a new API to obtain page icons, WebKit nightly builds for Epiphany Canary produced by GNOME GitLab, and more conservative checks for MPEG-4 Audio object types are all part of this week's edition of the WebKit periodical.

Cross-Port 🐱

A new API to obtain page icons (a.k.a. “favicons”) has been added to the GTK port. The new functionality reuses the recently added WebKitImage class and provides access to multiple page icons at once through the added WebKitImageList type, allowing applications to better choose an icon that suits their needs. Changes to the WebKitWebView.page-icons property are guaranteed to be done once per page load, when all icon images are available to be used. This new API has been also enabled for the WPE port, and the plan is to deprecate the old page favicon functionality going forward.

Added iOS support for dialog light dismiss, part of the experimental closedby attribute implementation.

Multimedia 🎥

GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.

canPlayType() is now more conservative regarding MPEG-4 Audio object types. This primarily affects AAC extensions: In the past, as long as there was an AAC decoder installed, WebKit was accepting any codec string that started with mp4a. Now it only accepts codec strings that correspond to object types that have widespread support. This can prevent accidental playback of newer formats like xHE-AAC, which many decoders don't yet support — for example, as of writing, FFmpeg support for xHE-AAC is only very recent and still incomplete.

canPlayType() now also reports support for Dolby AC-4 in systems with a decoder capable of handling it.

The GStreamer WebRTC backend now rejects SDP including rtpmap attributes in the disallowed range of 64-95 payload types. Compliance with RFC 7587 was also improved.

Infrastructure 🏗️

The WebKitGTK nightly builds for Epiphany Canary are now handled entirely by the GNOME GitLab infrastructure, many thanks to them! The previous approach was not optimal, producing release builds without debug symbols. With the new builds, it is now easier to get crash stack traces including more information.

That’s all for this week!

by Igalia WebKit Team at April 07, 2026 05:07 PM

March 30, 2026

Igalia WebKit Team

WebKit Igalia Periodical #61

Update on what happened in WebKit in the week from March 23 to March 30.

This week comes with a mixed bag of new features, incremental improvements, and a new release with the ever important security issue fixes. Also: more blog posts!

Cross-Port 🐱

Implemented initial support for closedby=any on dialog elements, which adds light dismiss behaviour. This is behind the ClosedbyAttributeEnabled feature flag.

Added the remaining values for the experimental closedby attribute implementation.

MiniBrowser now has a --profile-dir=DIR command line option that can be used to specify a custom directory where website data and cache can be stored, to test, for example, behavior in a clean session.

Multimedia 🎥

GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.

Video decoding limits had been enforced on HTMLMediaElement.canPlayType() so far, but they are now also enforced in MediaCapabilities queries.

Graphics 🖼️

Fixed several OpenGL state restoration bugs in BitmapTexture . These could cause a mismatch between the GL state assumed by Skia and the actual one, leading to rendering artifacts with certain GPU drivers and configurations.

The SKIA_DEBUG CMake option has been enabled for Debug builds, enabling Skia's internal assertions, debug logging, and consistency checks (e.g. bounds checking, resource key diagnostics). It remains off by default for Release and RelWithDebInfo builds, and can still be explicitly configured via -DSKIA_DEBUG=ON|OFF.

WPE WebKit 📟

WPE Platform API 🧩

New, modern platform API that supersedes usage of libwpe and WPE backends.

The new WPE_SETTING_OVERLAY_SCROLLBARS setting is now available, and disabling it will use a more traditional, always visible scrollbar style.

Releases 📦️

A new USE_GSTREAMER build option may now be used to toggle the features that require GStreamer at once. This can be used to effectively disable all multimedia support, which previously needed toggling four CMake options.

WebKitGTK 2.52.1 and WPE WebKit 2.52.1 have been released. On top of a small corrections typical of the first point releases in a new stable series, this one includes a number of fixes for security issues, and it is a recommended update. The corresponding security advisory, WSA-2026-0002 (GTK, WPE) has been published as well.

Community & Events 🤝

Simón Pena wrote a blog post showing how to create a minimal WPE launcher, which uses a Fedora Podman container with pre-built WPE WebKit libraries and a launcher with barely 10 lines of code to display a web view. This complements Kate Lee's custom HTML context menu blog post from last week.

That’s all for this week!

by Igalia WebKit Team at March 30, 2026 09:46 PM

March 20, 2026

Simón Pena

Getting started with WPE WebKit: a minimal launcher

My colleague Kate recently demonstrated on her blog how simple it is to write a WPE Platform-based launcher, and did so by building it side-by-side with MiniBrowser, inside the WebKit tree.

This entry takes one step back, and demonstrates the same concepts assuming you are not building WPE WebKit yourself, but rather getting it from your distribution. Many of the steps below would apply if you were using a Yocto/OpenEmbedded-based image, but that can be the focus of another post.

Getting WPE WebKit

Get WPE lists a number of options to get WPE from your preferred distribution. At the moment of writing, Fedora, Debian and ArchLinux are your best choices to get a recent version of WPE:

  • 2.52 on Fedora
  • 2.50 on Debian Forky, 2.52 on Debian Sid
  • 2.50 on ArchLinux

However, since WPE Platform hasn’t officially been released, we need to use Fedora, where my colleague Philippe maintains a Copr repository with it enabled.

sudo dnf copr enable -y philn/wpewebkit
sudo dnf install wpewebkit-devel

Alternatively, you can use a container. Here is a Containerfile based on Fedora 42:

FROM fedora:42

RUN dnf install -y \
    dnf-plugins-core \
    && dnf copr enable -y philn/wpewebkit \
    && dnf install -y \
    gcc-c++ \
    cmake \
    pkg-config \
    wpewebkit-devel

WORKDIR /src

Build and run it with:

podman build -t wpe-dev .
podman run -it -e WAYLAND_DISPLAY=$WAYLAND_DISPLAY \
-e XDG_RUNTIME_DIR=/run/user/$(id -u) \
-v $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY:/run/user/$(id -u)/$WAYLAND_DISPLAY \
-v /dev/dri:/dev/dri \
wpe-dev bash

The build system

Kate’s post builds the launcher as part of the WebKit tree using WebKit’s own CMake infrastructure. For a standalone project, we need a self-contained CMakeLists.txt that finds WPE WebKit through pkg-config:

cmake_minimum_required(VERSION 3.16)
project(wpe_sample CXX)

set(CMAKE_CXX_STANDARD 17)

find_package(PkgConfig REQUIRED)

# The Wayland WPE Platform already depends on wpe-platform-2.0
pkg_check_modules(WebKitDeps REQUIRED
    IMPORTED_TARGET
    wpe-webkit-2.0
    wpe-platform-wayland-2.0
)

add_executable(wpe_sample main.cpp)

target_link_libraries(wpe_sample
    PRIVATE
        PkgConfig::WebKitDeps
)

The launcher

Here is a minimal launcher — the smallest amount of code needed to display a web page with WPE WebKit:

#include <wpe/webkit.h>

int main(int argc, const char *argv[]) {
    g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, false);
    g_autoptr(WebKitWebView) view = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
        nullptr));
    webkit_web_view_load_uri(view,
        (argc > 1) ? argv[1] : "https://wpewebkit.org");
    g_main_loop_run(loop);
    return EXIT_SUCCESS;
}

This snippet relies heavily on default behaviours: it will create a default WPE view, with default top levels, with the default display selection behaviour (Wayland), default context, settings…

Again, Kate’s post does a more realistic job at showing how the various pieces are created and connected together.

Building and running

cmake -B build
cmake --build build
./build/wpe_sample https://wpewebkit.org/

WPE WebKit minimal launcher

Display backends

WPE WebKit can render to different display backends depending on your environment, which you can select through environment variables:

# Wayland (e.g. desktop, Weston).
WPE_DISPLAY=wpe-display-wayland WAYLAND_DISPLAY=wayland-1 ./build/wpe_sample https://wpewebkit.org/

# DRM/KMS (e.g. embedded, no compositor)
WPE_DISPLAY=wpe-display-drm ./build/wpe_sample https://wpewebkit.org/

# Headless (e.g. testing, CI)
WPE_DISPLAY=wpe-display-headless ./build/wpe_sample https://wpewebkit.org/

You can take a look at wpe_display_get_default() in WPEPlatform/wpe/WPEDisplay.cpp to understand how the automatic selection takes place in the absence of an explicit WPE_DISPLAY request.

(In our example, we are only listing Wayland as a CMake dependency. If libwpewebkit was compiled without DRM or headless support, the environment variable approach would not work.)

Next steps

This is all for now. The next entry in the series will cover classic kiosk features: preventing navigation to unwanted sites, controlling whether new windows can be opened, and intercepting requests through policy decisions.

For a more complete example that includes a custom HTML context menu and JavaScript injection, see Kate’s post.

by Simón at March 20, 2026 12:00 AM

March 18, 2026

Igalia WebKit Team

WebKit Igalia Periodical #60

Update on what happened in WebKit in the week from March 10 to March 18.

The big ticket item in this week's update are the 2.52.0 releases, which include the work from the last six-month development period, and come with a security advisory. Meanwhile, WPE-Android also gets a release, and a number of featured blog posts.

WPE WebKit 📟

Last week we added support to WPE MiniBrowser to load settings from a key file. This extended the existing --config-file=FILE feature, which previously only loaded WPEPlatform settings under the [wpe-platform] group. Now the feature uses webkit_settings_apply_from_key_file() to load properties such as user-agent or enable-developer-extras from the [websettings] group as well.

Releases 📦️

WebKitGTK 2.52.0 and WPE WebKit 2.52.0 are now available. These include the results of the effort made by the team during the last six months, including rendering improvements and performance optimizations, better security for WebRTC, a more complete WebXR implementation, and a second preview of the WPEPlatform API for the WPE port—among many other changes.

More information about the changes and improvements brought by these major releases can be found at the blog post about WebKitGTK 2.52, and the corresponding one for WPE WebKit 2.52.

Accompanying these releases there is security advisory WSA-2026-0001 (GTK, WPE), with information about solved security issues. As usual, we encourage everybody to use the most recent versions where such issues are known to be fixed.

Bug reports are always welcome at the WebKit Bugzilla.

WPE Android 0.3.3 has been released, and prebuilt packages are available at the Maven Central repository. This is a maintenance release which updates the included WPE WebKit version to 2.50.6 and libsoup to 3.6.6, both of which include security fixes.

Community & Events 🤝

Kate Lee wrote a very interesting blog post showing how to create a small application using the WPEPlatform API to demonstrate one of its newly available features: the Context Menu API. It is rendered entirely as an HTML overlay, enabling richer and more portable context menu implementations.

WebXR support for WebKitGTK and WPE has been reworked and aligned with the modern multi-process architecture, using OpenXR to enable XR device integration on Linux and Android. Sergio Villar wrote a blog post that explains all the work done in the last months around it.

That’s all for this week!

by Igalia WebKit Team at March 18, 2026 07:46 PM

WPE WebKit Blog

WPE WebKit 2.52 highlights

The WebKit team at Igalia is happy to announce a new release series of WPE WebKit. This is a summary of the most noteworthy changes from the latest release cycle.

Graphics improvements

WPE’s graphics support has seen numerous improvements with a positive impact in rendering performance, resource usage, and better rendering. Let’s have a look at some of the most significant changes:

  • Compute the layers tile size, using a different strategy depending on whether GPU rendering is enabled. This optimizes resource usage depending on both hardware and software rendering mode.
  • WPE now uses run-loop observers to properly schedule layer flushing and composition, which results in snappier and better performing rendering and animation.
  • 2D-canvas acceleration has now improved performance, as operations are recorded for batched replay.
  • Text rendering has better performance too.
  • In non-composite mode, it’s now also possible to use damage propagation.
  • Asynchronous scrolling has also seen performance improvements.

On top of this, as usual, many rendering issues have been fixed, making this release of WPE one of the best in terms of graphics support.

Multimedia improvements

WebRTC

When using GstWebRTC, WebRTC network access has been moved to the network process. This also requires librice, and building with the CMake USE_LIBRICE option. When this is enabled, it is still possible to choose the older libnice-based implementation at runtime by setting WEBKIT_GST_DISABLE_WEBRTC_NETWORK_SANDBOX=1 in the environment.

Having WebRTC network access in the network process is a security improvement, as it reduces the surface of attack in other more sensitive processes.

Other multimedia improvements

  • Videos with BT2100-PQ colorspace are now tone-mapped to SDR, ensuring colours do not appear washed out.
  • Support for the Audio Output Devices API, which allows Web content to enumerate audio devices and decide which one to use for output. This feature is disabled by default, and may be previewed using the ExposeSpeakers, ExposeSpeakersWithoutMicrophone, and PerElementSpeakerSelection feature flags.
  • Many code improvements to the GStreamer backend that will result in a more stable multimedia experience.

WebXR

WebXR support through OpenXR has seen substantial development this cycle:

API Changes

The future of the WPE API

The traditional libwpe-based API remains in WPE for this release cycle, but we are planning to sunset it starting with the following one (2.54). This applies to Cog, which is no longer in active development and won’t have any more stable releases beyond the 0.18.x series. While both libwpe and Cog will remain available, we encourage developers to transition to the new WPEPlatform API, which will be considered stable by then.

This means that it is the perfect time to test the WPEPlatform API and provide feedback, as it’s still possible to make changes to it to better suit users’ needs.

WPEPlatform API changes

New platform APIs include:

  • wpe_display_create_toplevel(). This way it’s possible to create a toplevel using the common API which allows the inspector to work when the application is handling toplevels.
  • A new WPEDisplay::disconnected signal has been added, which allows platform implementations to notify when the native display gets “disconnected” and thus no longer usable. Applications can handle it to attempt recovery, or to know when they may free resources.
  • A new WPEView::buffers-changed signal, alongside the associated WPEViewClass.buffers_changed virtual function, have been added. These may be used to know in advance which graphics buffers will be used for rendering the content for a given web view. This feature is mainly useful for platform implementations which may need to perform additional setup in advance, before updated web view contents are provided in the buffers configured by WebKit.
  • Two new functions, wpe_clipboard_content_get_text() and wpe_clipboard_content_get_bytes(), allow applications to obtain the contents held in the clipboard.

The public API has received the following changes, which might require changes to existing platform implementations:

  • Multiple callbacks are now supported for WPEScreenSyncObserver, the API has changed from wpe_screen_sync_observer_set_callback() to a pair of wpe_screen_sync_observer_add_callback()/_remove_callback() functions. The functions to start/stop the observer are no longer available, and instead the observer will be activated automatically when there are one or more callbacks attached to it.

The WPEPlatform API can now be used on Android.

Legacy API

The legacy libwpe-based API can be disabled at build time, by toggling the ENABLE_WPE_LEGACY_API CMake option. This allows removal of uneeded code when an application is exclusively using the new WPEPlatform API.

New WebKit API

Web Standards support

As usual, this list is not exhaustive as WebKit continuously progresses in its support for new standards. Some of the highlights for this release are:

Other notes

The Flatpak-based development SDK has been removed. Developers are encouraged to use the WebKit Container SDK instead.

March 18, 2026 12:00 AM

March 17, 2026

Sergio Villar

Implementing WebXR in WebKit for WPE

Since 2022, my main focus has been working on the Wolvic browser, still the only open source WebXR-capable browser for Android/AOSP devices (Meta, Pico, Huawei, Lenovo, Lynx, HTC…) out there. That’s an effort that continues to this day (although to a much lesser extent nowadays). In early 2025, as a consequence of all that work in XR on the web, an opportunity emerged to implement WebXR support in WebKit for the WPE port, and we decided to take it.

March 17, 2026 08:46 AM

March 16, 2026

Hironori Fujii

Async Scrolling Improvements

WPE WebKit and WebKitGTK support async scrolling for wheel events. I landed several improvements for the upcoming 2.52 release.

  • Bug 305451 – wheel event async scrolling doesn’t start while the main thread is blocked
  • Bug 305560 – rendering glitches for unpainted tiles
  • Bug 305561 – Paint scrollbars in the scrolling thread for async scrolling

Here are videos of before and after the changes. This is the test content.

There is still room for further improvement.

  • The scrollbar hiding animation timer is still running in the main thread.
    • It can use CoordinatedPlatformLayer::setAnimations.
    • Or CoordinatedPlatformLayer::setOpacity.
  • Add the showing animation and transition animations of mouse hover states like GTK Adwaita theme
  • Support touch and gesture events async scrolling

March 16, 2026 12:00 AM

Kate Lee

Building a Custom HTML Context Menu with the New WPEPlatform API

WPE WebKit is a WebKit port optimized for embedded devices — think set-top boxes, digital signage, kiosk displays, and in-vehicle infotainment systems. It is developed by Igalia and powers web experiences on millions of devices worldwide, from set-top boxes to smart TVs and beyond.

WPE WebKit has recently introduced a brand-new platform API called WPEPlatform, which replaces the legacy libwpe + wpebackend-fdo stack. In this post, I will walk you through building a minimal WPE browser launcher using only the new WPEPlatform API, and demonstrate one of its newly available features: the Context Menu API — rendered entirely as an HTML overlay.

Why a New API? #

The legacy stack (libwpe + wpebackend-fdo + Cog platform plugins) had several pain points: nested Wayland compositor complexity, dependency on Mesa’s now-deprecated EGL_WL_bind_wayland_display extension, rigid C function-pointer tables, and platform code scattered across three libraries.

The new WPEPlatform API replaces all of this with a single, clean GObject-based layer — providing automatic backend creation, DMA-BUF direct buffer sharing, unified window management (fullscreen, maximize, resize, title), and easy language bindings via GObject Introspection.

Timeline: The stable release of WPEPlatform is planned for September 2026. At that point, the legacy API will be officially deprecated. We strongly recommend new projects to adopt the WPEPlatform API from the start.

WPEPlatform Launcher: A Minimal Browser in ~250 Lines #

To demonstrate the new API, I built WPEPlatformLauncher — a minimal but functional WPE WebKit browser that uses only the WPEPlatform API. No legacy libwpe, no wpebackend-fdo, no Cog — just the new API.

The full source code is available at: kate-k-lee/WebKit@aed6402

How Simple Is It? #

Here is the core of the launcher — creating a WebView with the new API:

/* WPEPlatform backend is created automatically — no manual setup needed */
auto* webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
"web-context", webContext,
"network-session", networkSession,
"settings", settings,
"user-content-manager", userContentManager,
nullptr));

/* Get the WPEPlatform view — this is where the new API shines */
auto* wpeView = webkit_web_view_get_wpe_view(webView);
auto* toplevel = wpe_view_get_toplevel(wpeView);

/* Window management: fullscreen, resize, title — all built-in */
wpe_toplevel_fullscreen(toplevel);
wpe_toplevel_resize(toplevel, 1920, 1080);
wpe_toplevel_set_title(toplevel, "WPEPlatform Launcher");

/* Input events: just connect a GObject signal */
g_signal_connect(wpeView, "event", G_CALLBACK(onViewEvent), webView);

Compare this with the legacy API, which required:

  1. Manually creating a WPEToolingBackends::ViewBackend
  2. Wrapping it in a WebKitWebViewBackend with a destroy callback
  3. Creating a C++ InputClient class and registering it
  4. Having no window management (no maximize, minimize, title, etc.)

The new API handles backend creation, display detection, and input forwarding automatically.

Keyboard Shortcuts #

Handling keyboard events is straightforward with the WPEPlatform event system:

static gboolean onViewEvent(WPEView* view, WPEEvent* event, WebKitWebView* webView)
{
if (wpe_event_get_event_type(event) != WPE_EVENT_KEYBOARD_KEY_DOWN)
return FALSE;

auto modifiers = wpe_event_get_modifiers(event);
auto keyval = wpe_event_keyboard_get_keyval(event);

/* Ctrl+Q: Quit */
if ((modifiers & WPE_MODIFIER_KEYBOARD_CONTROL) && keyval == WPE_KEY_q) {
g_application_quit(g_application_get_default());
return TRUE;
}

/* F11: Toggle fullscreen via WPEToplevel */
if (keyval == WPE_KEY_F11) {
auto* toplevel = wpe_view_get_toplevel(view);
if (wpe_toplevel_get_state(toplevel) & WPE_TOPLEVEL_STATE_FULLSCREEN)
wpe_toplevel_unfullscreen(toplevel);
else
wpe_toplevel_fullscreen(toplevel);
return TRUE;
}

return FALSE;
}

HTML-Based Context Menu: Solving the “No Native UI” Challenge #

WPE WebKit is designed for embedded environments where there is no native UI toolkit — no GTK, no Qt. This means features like context menus (right-click menus) that desktop browsers take for granted need to be implemented by the application.

The approach: intercept WebKit’s context-menu signal, read the menu items, and render them as an HTML/CSS overlay injected into the page DOM.

The Architecture #

User right-clicks
  → WebKit emits "context-menu" signal
  → onContextMenu() handler:
      1. Reads menu items via webkit_context_menu_get_items()
      2. Gets position via webkit_context_menu_get_position()
      3. Builds JavaScript that creates DOM elements
      4. Injects via webkit_web_view_evaluate_javascript()
      5. Returns TRUE (suppresses default menu)

User clicks a menu item
  → JS: window.webkit.messageHandlers.contextMenuAction.postMessage(actionId)
  → C: onContextMenuAction() receives the action ID
      → Executes: webkit_web_view_go_back(), execute_editing_command("Copy"), etc.

User clicks outside the menu
  → JS: overlay click handler removes the DOM elements

Reading Context Menu Items #

The Context Menu API provides everything we need:

static gboolean onContextMenu(WebKitWebView* webView,
WebKitContextMenu* contextMenu, gpointer /* event */,
WebKitHitTestResult* hitTestResult, gpointer)
{
/* Save hit test result for link-related actions */
savedHitTestResult = WEBKIT_HIT_TEST_RESULT(g_object_ref(hitTestResult));

/* Iterate through menu items */
GList* items = webkit_context_menu_get_items(contextMenu);
for (GList* l = items; l; l = l->next) {
auto* item = WEBKIT_CONTEXT_MENU_ITEM(l->data);

if (webkit_context_menu_item_is_separator(item)) {
/* Render as a horizontal line */
continue;
}

const char* title = webkit_context_menu_item_get_title(item);
auto action = webkit_context_menu_item_get_stock_action(item);
/* Build HTML element with title and action ID */
}

/* Get position for menu placement */
gint posX = 0, posY = 0;
webkit_context_menu_get_position(contextMenu, &posX, &posY);

return TRUE; /* Suppress default menu */
}

The HTML Menu: Dark Theme for Embedded #

The context menu is rendered with a dark theme CSS, designed for embedded/kiosk displays:

#__wpe_ctx_menu {
position: fixed;
min-width: 180px;
background: #2b2b2b;
border: 1px solid #505050;
border-radius: 6px;
padding: 4px 0;
box-shadow: 0 8px 24px rgba(0,0,0,0.4);
font-family: system-ui, sans-serif;
font-size: 13px;
color: #e0e0e0;
}

.__wpe_ctx_item:hover {
background: #0060df;
color: #ffffff;
}

Handling Actions via Script Message Handler #

Communication between the HTML menu and the C application uses WebKit’s script message handler mechanism:

/* Register message handler */
auto* ucm = webkit_user_content_manager_new();
webkit_user_content_manager_register_script_message_handler(
ucm, "contextMenuAction", nullptr);
g_signal_connect(ucm, "script-message-received::contextMenuAction",
G_CALLBACK(onContextMenuAction), nullptr);
// In the generated HTML menu item:
item.addEventListener('click', function() {
window.webkit.messageHandlers.contextMenuAction.postMessage(actionId);
});
/* Handle the action in C */
static void onContextMenuAction(WebKitUserContentManager*, JSCValue* value, gpointer)
{
int actionId = jsc_value_to_int32(value);

switch (actionId) {
case WEBKIT_CONTEXT_MENU_ACTION_RELOAD:
webkit_web_view_reload(webView);
break;
case WEBKIT_CONTEXT_MENU_ACTION_COPY:
webkit_web_view_execute_editing_command(webView, "Copy");
break;
case WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK:
webkit_web_view_load_uri(webView,
webkit_hit_test_result_get_link_uri(savedHitTestResult));
break;
/* ... more actions ... */
}
}

Demo #

Here is the WPEPlatformLauncher in action, showing the HTML context menu with various actions:

WPEPlatformLauncher context menu demo

Right-clicking shows the HTML context menu. Clicking “Reload” triggers an actual page reload.

Context menu on a link

Right-clicking a link shows link-specific actions like “Open Link” and “Copy Link Address”.

Building and Running #

I built and ran the WPEPlatformLauncher inside a container using the WebKit Container SDK, which provides a pre-configured development environment with all the dependencies needed to build WPE WebKit.

The WPEPlatformLauncher integrates into the WebKit build system:

# Build WPE WebKit with the launcher
Tools/Scripts/build-webkit --wpe --release

# Run
./WebKitBuild/WPE/Release/bin/WPEPlatformLauncher https://wpewebkit.org

# Run in fullscreen (kiosk mode)
./WebKitBuild/WPE/Release/bin/WPEPlatformLauncher --fullscreen https://your-app.com

The full source is a single main.cpp file (~600 lines including the context menu), integrated into the WebKit tree alongside MiniBrowser:

WebKit/Tools/
├── MiniBrowser/wpe/          ← Existing (supports both old + new API)
├── WPEPlatformLauncher/      ← New (WPEPlatform API only)
│   ├── main.cpp
│   └── CMakeLists.txt
└── PlatformWPE.cmake         ← Modified to add WPEPlatformLauncher

Summary #

The new WPEPlatform API makes building WPE WebKit applications significantly simpler:

  • No manual backend setup — the platform is detected and configured automatically
  • GObject-based — signals, properties, and ref counting instead of C function pointers
  • DMA-BUF direct sharing — no dependency on Mesa’s deprecated EGL extensions
  • Unified window management — fullscreen, maximize, minimize, resize, and title
  • Language binding friendly — works with Python, JavaScript, and more via GObject Introspection

For embedded browser developers building kiosk UIs, set-top box interfaces, or digital signage with WPE WebKit — now is the time to adopt the new API. The stable release is coming in September 2026, and the legacy stack (libwpe, wpebackend-fdo, Cog) will be deprecated at that point.

Resources #

March 16, 2026 12:00 AM

March 11, 2026

Hironori Fujii

Building WebKit and libsoup with AddressSanitizer (ASan)

I built libsoup and WebKit with ASan today. It works almost out of the box. I used Clang. GCC also supports ASan, but WebKit has a problem with it. WebKit Container SDK is based on Ubuntu 20.04 LTS at the moment. It contains clang 18 by default.

Installed required packages.

sudo apt install libclang-rt-18-dev llvm-18-dev

Set env vars.

export CC=clang CXX=clang++

Passed some flags to libsoup.

--- /jhbuild/webkit-sdk-deps.modules.orig
+++ /jhbuild/webkit-sdk-deps.modules
@@ -149,7 +149,7 @@
</dependencies>
</meson>

- <meson id="libsoup" mesonargs="-Dtests=false">
+ <meson id="libsoup" mesonargs="-Dtests=false -Db_sanitize=address -Db_lundef=false">
<branch repo="github.com"
checkoutdir="libsoup"
module="GNOME/libsoup.git" tag="3.6.6"/>

Then, build and install libsoup.

jhbuild buildone -f libsoup

Then, build WebKit with ASan.

./Tools/Scripts/build-webkit --gtk --release --cmakeargs=-DENABLE_SANITIZERS=address

WebKit has a lot of memory leaks by design. Don’t detect leaks.

export ASAN_OPTIONS=detect_leaks=0

For run-webkit-tests, I had to modify a script a bit.

diff --git a/Tools/Scripts/webkitpy/port/driver.py b/Tools/Scripts/webkitpy/port/driver.py
index eb12801a455b..c9f74eeab4e2 100644
--- a/Tools/Scripts/webkitpy/port/driver.py
+++ b/Tools/Scripts/webkitpy/port/driver.py
@@ -482,7 +482,7 @@ class Driver(object):
else:
environment['DUMPRENDERTREE_TEMP'] = str(self._driver_tempdir)
environment['LOCAL_RESOURCE_ROOT'] = str(self._port.layout_tests_dir())
- environment['ASAN_OPTIONS'] = "allocator_may_return_null=1"
+ environment['ASAN_OPTIONS'] = "allocator_may_return_null=1:detect_leaks=0"
environment['__XPC_ASAN_OPTIONS'] = environment['ASAN_OPTIONS']

# Disable vnode-guard related simulated crashes for WKTR / DRT (rdar://problem/40674034).

That’s it. Enjoy.

March 11, 2026 12:00 AM

March 09, 2026

Igalia WebKit Team

WebKit Igalia Periodical #59

Update on what happened in WebKit in the week from March 2 to March 9.

As part of this week's handful of news, WebKitGTK and WPE WebKit now have support for Gamepad's "VibationActuator" property, the video decoding limit is now configurable at runtime in addition to build time, and an interesting fix that makes WebKit render fonts like other browsers by making it blend text incorrectly (!).

Cross-Port 🐱

Using libmanette's rumble support, enabled Gamepad VibrationActuator for WebKitGTK and WPE WebKit.

With these changes, playEffect() can be used to play dual-rumble vibration effects.

Multimedia 🎥

GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.

VIDEO_DECODING_LIMIT is now configurable at runtime, in addition to build time. That will allow vendors that share a single binary build on different platforms to fine-tune their needs without a rebuild.

Graphics 🖼️

Landed a change that tweaks the text rendering done with Skia. With this change, the text looks more natural now - just like in other browsers. However, this is done by blending text incorrectly as a compromise.

Releases 📦️

One more set of release candidates for the upcoming stable branch, WebKitGTK 2.51.93 and WPE WebKit 2.51.93, have been published. For those interested in previewing the upcoming 2.52.x series this release is expected to be quite stable. Reporting issues in Bugzilla are, as usual, more than welcome.

That’s all for this week!

by Igalia WebKit Team at March 09, 2026 08:02 PM

March 02, 2026

Igalia WebKit Team

WebKit Igalia Periodical #58

Update on what happened in WebKit in the week from February 23 to March 2.

This installment of the periodical brings news about support for Qualcomm qtivdec2 and qtivenc2 on GStreamer, GPU texture atlas creation and replay substitution, enhancement of the scroll gesture in WPE, and two new releases: WebKitGTK 2.51.92 and WPE WebKit 2.51.92.

Cross-Port 🐱

Multimedia 🎥

GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.

Work on adding support for the Qualcomm GStreamer qtivdec2 and qtivenc2 elements is on-going

Graphics 🖼️

Implemented GPU texture atlas creation and replay substitution in the Skia painting engine on GTK/WPE. After recording, raster images are packed into GPU atlases via BitmapTexture, with two upload paths: an optimized DMA-buf path that memory-maps GPU buffers and dispatches uploading to a dedicated worker thread, and a synchronous GL fallback using BitmapTexture::updateContents(). Atlas uploads are synchronized across workers using a countdown-latch fence. During replay, SkiaReplayCanvas intercepts raster image draws and substitutes them with atlas texture draws, mapping source coordinates into atlas space.

WPE WebKit 📟

WPE Platform API 🧩

New, modern platform API that supersedes usage of libwpe and WPE backends.

The recent WPE WebKit 2.51.92 release is the first one to have its WPEPlatform documentation online, but it was not included in the tarball. This issue has been corrected and tarballs for future releases will also include this documentation.

Scrolling using touch input with WPEPlatform would result in scrolling faster when more than one touch point was in effect. The gesture detector has been fixed to make scrolling have always a consistent speed.

Releases 📦️

The third —and likely the last— release candidates for the upcoming stable branch, WebKitGTK 2.51.92 and WPE WebKit 2.51.92, have been published. For those interested in previewing the upcoming 2.52.x series this release is expected to be quite stable; but there might be still some rough edges. Reporting issues in Bugzilla are, as usual, more than welcome.

That’s all for this week!

by Igalia WebKit Team at March 02, 2026 08:11 PM

February 23, 2026

Igalia WebKit Team

WebKit Igalia Periodical #57

Update on what happened in WebKit in the week from February 9 to February 23.

In this week we have a nice fix for video streams timestamps, a fix for a PDF rendering regression, support for rendering video buffers provided by Qualcomm video decoders, and a fix for a font selection issue. Also notable we had a new WPE Android release, and the libsoup 3.6.6 release.

Cross-Port 🐱

Added a new webkit_feature_list_find() convenience function to the public API, which searches for a WebKitFeature given its identifier.

Multimedia 🎥

GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.

Graphics 🖼️

Fixed a PDF rendering regression caused by the canvas 2D operation recording feature, where switching between the recording canvas and the GPU surface canvas failed to preserve the full save/restore nesting, clip stack, and transparency layer state. Replaced the fragile state-copying approach with a state replay mechanism in GraphicsContextSkia that tracks the full sequence of save restore, clip, and transparency layer operations, then reconstructs the exact nesting on the target canvas when flushing a recording.

Added support for rendering video buffers provided by Qualcomm hardware-accelerated decoders, with aid from the EXT_YUV_target OpenGL extension.

Fixed the font selection issue that the system fallback font cache mixed up different font styles.

Releases 📦️

WPE Android 0.3.2 has been released, and prebuilt packages are available at the Maven Central repository. This is a stable maintenance release which updates WPE WebKit to 2.50.5, which is the most recent stable release.

libsoup 3.6.6 has been released with numerous bug and security fixes.

That’s all for this week!

by Igalia WebKit Team at February 23, 2026 07:52 PM