[SOLVED] Multi-threaded operations in WebXR; Editor vs Published

Issue: Main thread in WebXR application stalls in published mode, but not in Editor->Launch. Video with commentary at link below (sorry the audio is muffled). Are published links using header; Origin-Agent-Cluster to turn off multi-threading?

The scene “0 - Published Showcase”, which is what was published. Works from Editor, but not when published at https://playcanvas.com/project/873970/overview/webxrpress-library

Backgound: So this is a strange one. I’ve got an iframe that’s essentially running some rendering tasks in the background. This works well in the editor, but not when published. I’ve simulated the issue further by intentionally running a “CPU intensive task” on top of the rendering which is the real-time HTML console window itself (from https://gist.github.com/sqren/5083d73f184acae0c5b7).

Usually the web browser will dedicate a thread to a given domain in an iframe; a feature of most Chrome (88+) based browsers, including what’s found in the Oculus Quest. Now there is a new setting that web servers can issue in response headers (maybe as new as 2021?) that has to do with “Origin-Agent-Cluster”. This specifically tells the browser to enable or disable the allocation of resources for things like embedded content. I’m not sure if this is the source of the issue (more info about the setting here: Requesting performance isolation with the Origin-Agent-Cluster header)

Video showing the main thread locking up movement and hand controller tracking (again, only in Published mode):

Any clues greatly appreciated!

Update: origin-agent-cluster doesn’t appear to be set or doesn’t seem to be the cause of the issue AFAIK. According to docs; the window.originAgentCluster would contain a value and I don’t see that from either links (Published or Launched) when using Firefox on the desktop.

@yak32 Is this something that you can look at/investigate?

@Steveorevo Have you tried hosting this locally with the agent header added just to check that the published code and assets are fine?

Thanks for the suggestions. I’ve gone ahead and tried a self-hosting example (which was incredibly easy; kudos to the creators!) at:


This was exported and downloaded using the publish feature’s default options. The zip file was uploaded to a typical cPanel hosting provider and upzipped.

I also tried publishing with the option not to concatenate scripts; in hopes to better simulate what Editor->Launch delivers. Same result.


It is experiencing the same stalling; clearly the iframe processes are not running in their own thread. I wonder what the Editor → Launch has that a published work doesn’t? Looks like there’s some websockets stuff for realtime development; I will try to examine the differences in https:// delivered source…

Thats weird that it also happens on self hosting :thinking:

I was thinking that it might have to do with OOPIFS (Out of Process iframes) settings. So I tried publishing in a fork, with the iframe style settings of visibility:hidden and again with display:none; as documentation indicates that OOPIFS was designed to understand that a hidden iframe is often used for background processes. No luck. The latter (display:none) stops all canvas rendering but the math intensive function I set off every 3 seconds still stalls the main thread; so we know the iframe is there still running but in-process, or at least causing the parent to stall. Very weird how it works perfectly from Editor → Launch.

I found the solution! Turns out my first instinct was right, it was origin-agent-cluster!!! or rather the implicit setting of this attribute that unlocks multi-threading in iframes. I tried adding the response header to the iframes to no effect; but when I added it to the parent page it worked immediately! The solution on a self-hosted PHP enabled server is simple:

  1. Rename the index.html to index.php to leverage PHP’s header function.
  2. Append to the top of the file the following:
<?php header('Origin-Agent-Cluster: ?1'); ?>
  1. Enjoy!!! i.e at https://postmy.info/oo

The potential here is great as we can now unlock the full potential of the Quest’s Snapdragon-XR2 processor for our WebXR creations. Now the question is why did this work in Launch → Editor but not on Published? The answer lies in the aforementioned article by Domenic Denicola.

"These days browsers are more sophisticated, and try to separate different origins into different processes. How exactly this works varies per browser…they use heuristics… These heuristics are not perfect.

The fact that it worked in Launch->Editor is a “spoof”. Without setting the origin-agent-cluser response header, it’s really up to the browser’s own ‘heuristics’ to determine when to employ processes and threads and when not too. When I use the Launch->Editor, the memory footprint is a bit larger because PlayCanvas uses more resources than the lean-and-mean published version (i.e. websockets to the IDE, metrics gathering, One-Trust privacy management, etc). This pushes the client browser into using more processes which just happens to make things run smoother.

Therefore, if it is at all possible, I would like to request, with very strong emphasis on request (implore really :crazy_face:) that PlayCanvas simply add the response header Origin-Agent-Cluster: ?1 to both the Editor->Launch nginx server and (more importantly if possible) the “Publish” Amazon servers.

This feature alone will allow us to unlock a plethora of functionality for WebXR experiences, voice services, low-latency multi-user connections, sleek background rendering effects, etc. etc. That little setting will allow me to drain batteries and wow visitors with native app like special effects galore! Please, please, please add it if at all possible. :pray: :pray: :pray:

You can mark this thread as solved in the interim. You guys are awesome and have a great weekend!!!