WebBrowserComponent - thanks!

Just felt that I should say “Thank you!” to the JUCE devs for the WebBrowserComponent, which has allowed us to make major improvements to Wotja in version 22.3.0 (out in 1-2 weeks).

I’m particularly happy that you went to the effort of implementing the code behind JUCE_USE_WIN_WEBVIEW2, which makes a huge difference on Windows.

Thank you so much!

Pete - Intermorphic


Hi folks!

Wotja 22.3.0 is now available for download for macOS and Windows - and will be there in a day or so for iOS and Android (where we’re just waiting for reviews to complete).

We’re really happy with the new, tightly integrated in-app help system. We hope you like it!

It just goes to show how far you can go with in-app help, even in the context of a plug-in.

Thanks in no small part to JUCE.

Best wishes,


1 Like

Worth mentioning that anybody wanting a few more pointers on handling this, especially on Windows and Android, might want to see this thread:

(removed broken link)

Best wishes,


Your link’s broken

Hi @jrlanglois that is interesting - I just tried it, and it is working for me!

Most puzzling!

I’ve just tried to re-edit it the link.



Well I never!

Here is the link with spaces in to break it up!

(removed broken link)


still broken.

@peteatjuce the link isn’t the problem, I guess the issue is that it’s just a message thread between the two of us. Totally fine by me to share but i dont know how to do that…


@gm1 yeah, that has got me puzzled too then!!


Hi all,

Now that I’ve realised that link was actually from a private message thread :), the gist of the problem as discussed with @gm1 is easy enough to show with Wotja 22 on Windows 10:

  1. Using FL studio 20 or Ableton Live 11…
  2. Open Wotja VST3 the first time to get the Web View Component based help window
  3. Close or collapse the whole plugin window (not the help window)
  4. Reopen the plugin
  5. The frame of the help window is still there but the Web View Component is gone (transparent)

@gm1 has seen exactly the same issue with their plug-in, so it sounds like a JUCE generic issue of some sort.

Best wishes, Pete

1 Like

And here is what I shared with @gm1 about my WebBrowserComponent code; we didn’t see anything obviously wrong with it.

Depending on platform, I use a Component like this:

#if defined(IM_TARGET_TVOS)
class MyWebBrowserComponent : public juce::Component {
#elif defined(IM_TARGET_WINDOWS)
class MyWebBrowserComponent : public juce::WindowsWebView2WebBrowserComponent {
#else // defined(IM_TARGET_WINDOWS)
class MyWebBrowserComponent : public juce::WebBrowserComponent {
#endif // defined(IM_TARGET_WINDOWS)

#if defined(IM_TARGET_TVOS)
  MyWebBrowserComponent(WJX_OnboardScreenVC* parent)
    : juce::Component(),
#elif defined(IM_TARGET_WINDOWS)
  MyWebBrowserComponent(WJX_OnboardScreenVC* parent)
    : juce::WindowsWebView2WebBrowserComponent(
        false, [] {
          juce::File appOrDLLPath = juce::File::getSpecialLocation(juce::File::currentApplicationFile);
          juce::File parentFolderToAppOrDLL = appOrDLLPath.getParentDirectory();
          juce::File webView2LoaderFile     = parentFolderToAppOrDLL.getChildFile("WebView2Loader.dll");

          auto userDataFolder = ImFile::sGetTmpFolder(ImContext::sGetImContextSingleInstanceApp());
          juce::File jUserDataFolder(juce::String::fromUTF8(userDataFolder.getFilePath().c_str()));
          return juce::WebView2Preferences()
#else // defined(IM_TARGET_WINDOWS)
  MyWebBrowserComponent(WJX_OnboardScreenVC* parent) : juce::WebBrowserComponent(false),
#endif // defined(IM_TARGET_WINDOWS)
#if defined(IM_TARGET_TVOS)
#else // defined(IM_TARGET_TVOS)
#endif // defined(IM_TARGET_TVOS)

So, nothing very special there; on Windows I use a special version of the browser that renders better on modern Windows platforms (e.g. allows it to embed svg images, and uses a nicer font etc.). NB: WJX_OnboardScreenVC is simply a variant of juce::Component, that owns the instance of MyWebBrowserComponent.

When I create the instance, I do this:

  webBrowser = std::make_shared<MyWebBrowserComponent>(this);
  webBrowser->setBounds(0, 0, 200, 200); // Required for page load to work...

Note the comment in the second line of code; just FWIW.

Other than that, the way I handle the virtual methods is as follows:

#if defined(IM_TARGET_TVOS)
#else // defined(IM_TARGET_TVOS)
bool MyWebBrowserComponent::pageAboutToLoad (const juce::String& newURL) {
  if (newURL.startsWith("http")) {
    // https reference - use external browser
    // Return false, to stop the navigation happening internally!
    return false;

  if (newURL == "about:blank") {
    // Required for Android!
    return false;

  return true;

// You can override this method to show some other error page by calling
// goToURL. Return true to allow the browser to carry on to the internal
// browser error page.
bool MyWebBrowserComponent::pageLoadHadNetworkError (const juce::String& errorInfo)  {

#ifdef IM_DEBUG
  im_trace("IM_DEBUG: MyWebBrowserComponent::pageLoadHadNetworkError (%s)\n", errorInfo.toUTF8().getAddress());
#endif // IM_DEBUG

  ImThread::sDelayToMainThread(std::chrono::milliseconds(200), [this]() {
    // Required on Android, otherwise ERROR is displayed

  return false; // Required on Android!

// This callback occurs when the browser attempts to load a URL in a new window.
// This won't actually load the window but gives you a chance to either launch a
//  window yourself or just load the URL into the current window with goToURL().
void MyWebBrowserComponent::newWindowAttemptingToLoad (const juce::String& newURL) {

// This callback happens when the browser has finished loading a page.
void MyWebBrowserComponent::pageFinishedLoading (const juce::String& url) {
  // Re-establish z-order of overlaid components.
  // Seems to be necessary for Android!



void WJX_OnboardScreenVC::fixZOrdering() {
  // Make sure the components that we use to overlay the WebView, remaining on top; especially for Android...
#endif // defined(IM_TARGET_TVOS)

I hope there is some clue in there...

Hoping that all helps somebody else,