<- Back to Blog

Why I hate WebKit, a (non) love letter

My experience working with WebKit, and why we are almost ditching it at Hopp

costa-alexoglou
Costa Alexoglou ·
Why I hate WebKit, a (non) love letter

Contents#

Intro#

Do you recognise the following page?

Can I use screenshot
caniuse.com

If you do, it means that at some point in your life, something did not work in a browser. There is an 80% chance, based on a quick Fermi estimate, that the browser was Safari (WebKit).

In this post, I will explain, based on my own experience, why I hate WebKit and the problems we keep hitting while building Hopp.

At the end, I will explain why we are committed to building the screensharing UI inside Hopp's app in Rust, without being Rust-pilled. 🦀

History#

A brief history of how we got here. Early in our journey, we had to decide how to build Hopp.

Electron vs Tauri decision
How we felt choosing a framework

We did some research, wrote an article comparing Electron vs Tauri, and decided to go with Tauri.

The reason to use a framework in the first place was to support all major platforms faster: macOS first, then Windows, and then Linux.

Naive at that point, we saw that Tauri was lighter, and that's what we needed, not another Electron app (which at this point is more of a meme).

Electron meme
Source: https://www.reddit.com/r/ProgrammerHumor/comments/7ex7t9

Little did we know the issues we were going to face as the product matured and we needed to support more features. Let's break down the WebKit issues we faced and still face.

Last point before I give you my list of pain-points, I want to provide context of what Hopp is.

Hopp is a remote pair programming app, built for super low-latency screensharing and remote control. That means we need to be careful with resource usage (CPU cycles on developers' machines matter), while keeping latency under <100ms. Per Apple's design guidelines, 100ms is around the threshold where interactions start to feel clunky, or in our case, where it feels like you are not controlling your own computer.

SVG Shadows are just not working properly#

There are many complaints about blurry SVGs in WebKit, on both iOS and macOS.

Here are our cursors from the website animation, and how they look in Chrome vs Safari.

Cursor blur in gethopp.app
How blurry SVGs look with filters

To avoid this in our desktop app, we compromised on design and removed blur effects.

Designers regularly hand developers components from Figma with multiple filters, so this issue is more relevant than ever. WebKit still does not ship a fix.

WebKit in iOS breaking without any breadcrumbs#

The latest iOS update introduced an error that I have never experienced in my 10+ years of deploying websites. It's a website. How hard can it be?

When visitors loaded our webpage in Safari, after a couple of seconds they would see: "A problem repeatedly occurred".

iOS problem occurred
Source: https://discussions.apple.com/thread/253213554

No errors in the console, no traces to tell us what happened.

Turns out, putting three GIFs on your landing page can crash the page on iOS 🥲

To fix this, we used IntersectionObserver to render the GIFs only when they were close to the current viewport. It shouldn't be that hard.

iOS problem occurred with multiple GIFs
Who would have though 3 GIFs can blow up the website

Pain to work with user agent#

LiveKit provides a Krisp integration for active noise cancellation. It sounds great, but it was not supported in Tauri.

After a long investigation, it turns out that Apple's WebKit engine version in the user agent is stale, always set to 605.1.15.

If you know why, please enlighten me. It makes feature-gating based on WebKit's engine version painful.

To solve this, we monkey-patched LiveKit's SDK to always return true for "is Krisp is supported?" question, so we went with an EAFP approach.

Audio adjustments and glitches#

If a user has music playing in the background, this becomes prominent, and this happens even in Safari when you join Google Meet.

There are two issues:

  1. There is a sound glitch when WebKit lists all the available microphones.
  2. WebKit reduces the sound from other audio streams when we have the microphone open.

Not sure though, if this is deliberate, or if it's a bug.

PS: If you enjoyed the music playing in this video, is a set from Solomum in Boiler Room.

New codec support#

From our internal tests, AV1 is the king of encoders for HD, low-latency streaming.

Unfortunately, WebKit supports AV1 only on newer devices that have a hardware decoder. Chrome supports it with a fallback to a software implementation when hardware acceleration is not available.

AV1 support in Safari
AV1 support in Safari from caniuse.com

Chrome's approach makes developers' lives easier, since you do not need to worry about one participant lacking AV1 support.

WebKitGTK does not support WebRTC#

We are building a remote pair programming app, so we use WebRTC heavily. Many developers asked us for Linux support, and we wanted to make it happen.

To understand where we use WebRTC, the image below helps.

Hopp app windows
All the windows that use WebRTC in Hopp's app

We have three windows that use WebRTC:

  1. Main window: When you start a call we start the audio stream from this window
  2. Screensharing window: This is where we stream the video from the sharer of the call and where you can remotely control your teammate's computer
  3. The camera view: This is where we stream webcam feeds, and audio (to be more in sync)

We found out much later than we would have liked that the default WebKitGTK build does not support WebRTC. PITA, since it blocked Linux support.

For completeness:

  1. WebKitGTK can support WebRTC, but it needs a custom build
  2. WebKitGTK is a port of WebKit

We also have a detailed issue around Linux support: gethopp/hopp#43

Why we will move to a Rust based window#

Now that you got a taste of why we have such a hard time with WebKit and Tauri for our use case, it's time to explain why we are not switching to Electron, and why we will port some crucial windows to Rust (with iced).

The options we considered before making this decision are below.

Tauri CEF#

One option would be to wait for CEF (Chromium Embedded Framework) support in Tauri, but there is no delivery date in sight. You can read more about CEF in Tauri in this GitHub discussion.

This would solve many problems, like inconsistent rendering of elements across OS, but it raises the question of whether Tauri becomes a framework like Electron.

Switch to Electron#

This would change a lot for us and would require a one-off manual update, since we rely on the Tauri updater for app updates.

Another reason is that we can centralize the whole business logic in the backend, without having to synchronize multiple windows and a separate app backend.

Why a Rust implementation#

As I stated before, one of the things we expect to win is simplicity in our codebase, where all the streaming logic will be on the backend side and not scattered in multiple places (Rust and WebKit windows).

To give you an example, because we have multiple WebKit windows and a Rust backend, we currently generate three LiveKit tokens for each user:

  • One for capturing and showing the screen share.
  • One for audio and camera sharing.
  • One for showing the camera view.

This means each person connects as three different participants in a call. Moving everything WebRTC-related to the backend will mean that we can have only one participant per person.

As mentioned above, showing the screen share stream from the backend will free us from browser restrictions on the codecs used. We will be able to use any codec libwebrtc supports, which is what the LiveKit Rust SDK uses.

Finally, having the buffers accessible on the backend side means we can provide features that would not be easily accessible in the browser.

For example, we are considering experimenting with image upscaling on macOS, similar to what Multi.app implemented. This means that even with lower quality streaming, you still get a crystal clear image with minimal overhead using Apple's M-chip Neural Engine.

Upscaling with Neural Engine
Image upscaling using ANE - Apple Neural Engine, image from Multi's blog

Ditch the frustrating "Can you see my screen?" dance.

Code side-by-side, remotely.

Get started

Conclusion#

I hope this breakdown made my frustration with WebKit clear.

There is no single "right" answer on whether you should ditch WebKit (and Tauri). We have particular use cases (we are all snowflakes, right?) that make things complicated. Many apps would have close to zero problems.

If you have questions or want to discuss this further, feel free to reach out on X/Twitter or email me directly at costa@gethopp.app.

webkit
remote pair-programming
development
GET STARTED

Pair program like you're in the same room

Built for developers who refuse to compromise. Open-source, affordable, and fast enough to keep you in flow.