diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 95f33f0170..480928ccd2 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2369,6 +2369,7 @@ void Application::initializeUi() {
 
     // Pre-create a couple of Web3D overlays to speed up tablet UI
     auto offscreenSurfaceCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
+    offscreenSurfaceCache->reserve(TabletScriptingInterface::QML, 1);
     offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2);
 }
 
diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp
index 0807d1c117..c8433766b9 100644
--- a/interface/src/ui/overlays/Web3DOverlay.cpp
+++ b/interface/src/ui/overlays/Web3DOverlay.cpp
@@ -62,6 +62,7 @@ static const float OPAQUE_ALPHA_THRESHOLD = 0.99f;
 
 const QString Web3DOverlay::TYPE = "web3d";
 const QString Web3DOverlay::QML = "Web3DOverlay.qml";
+
 Web3DOverlay::Web3DOverlay() : _dpi(DPI) {
     _touchDevice.setCapabilities(QTouchDevice::Position);
     _touchDevice.setType(QTouchDevice::TouchScreen);
@@ -97,6 +98,10 @@ Web3DOverlay::~Web3DOverlay() {
     }
 }
 
+void Web3DOverlay::rebuildWebSurface() {
+    destroyWebSurface();
+    buildWebSurface();
+}
 
 void Web3DOverlay::destroyWebSurface() {
     if (!_webSurface) {
@@ -136,17 +141,23 @@ void Web3DOverlay::buildWebSurface() {
         return;
     }
     gl::withSavedContext([&] {
-        _webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(pickURL());
         // FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces
         // and the current rendering load)
         if (_currentMaxFPS != _desiredMaxFPS) {
             setMaxFPS(_desiredMaxFPS);
         }
-        loadSourceURL();
-        _webSurface->resume();
+
+        if (isWebContent()) {
+            _webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(QML);
+            _webSurface->getRootItem()->setProperty("url", _url);
+            _webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
+        } else {
+            _webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(_url);
+            setupQmlSurface();
+        }
+        _webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
         _webSurface->resize(QSize(_resolution.x, _resolution.y));
-        _webSurface->getRootItem()->setProperty("url", _url);
-        _webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
+        _webSurface->resume();
     });
 
     auto selfOverlayID = getOverlayID();
@@ -187,88 +198,61 @@ void Web3DOverlay::update(float deltatime) {
     Parent::update(deltatime);
 }
 
-QString Web3DOverlay::pickURL() {
+bool Web3DOverlay::isWebContent() const {
     QUrl sourceUrl(_url);
     if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" ||
         _url.toLower().endsWith(".htm") || _url.toLower().endsWith(".html")) {
-        if (_webSurface) {
-            _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
-        }
-        return "Web3DOverlay.qml";
-    } else {
-        return QUrl::fromLocalFile(PathUtils::resourcesPath()).toString() + "/" + _url;
+        return true;
     }
+    return false;
 }
 
-void Web3DOverlay::loadSourceURL() {
-    if (!_webSurface) {
-        return;
-    }
+void Web3DOverlay::setupQmlSurface() {
+    _webSurface->getSurfaceContext()->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
+    _webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
+    _webSurface->getSurfaceContext()->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
+    _webSurface->getSurfaceContext()->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
+    _webSurface->getSurfaceContext()->setContextProperty("Vec3", new Vec3());
+    _webSurface->getSurfaceContext()->setContextProperty("Quat", new Quat());
+    _webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
+    _webSurface->getSurfaceContext()->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
+    _webSurface->getSurfaceContext()->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
 
-    QUrl sourceUrl(_url);
-    if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" ||
-        _url.toLower().endsWith(".htm") || _url.toLower().endsWith(".html")) {
+    if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") {
+        auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
+        auto flags = tabletScriptingInterface->getFlags();
 
-        _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
-        _webSurface->load("Web3DOverlay.qml");
-        _webSurface->resume();
-        _webSurface->getRootItem()->setProperty("url", _url);
-        _webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
-
-    } else {
-        _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath()));
-        _webSurface->load(_url, [&](QQmlContext* context, QObject* obj) {});
-        _webSurface->resume();
-
-        _webSurface->getSurfaceContext()->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("offscreenFlags", flags);
+        _webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("Account", AccountScriptingInterface::getInstance());
+        _webSurface->getSurfaceContext()->setContextProperty("Audio", DependencyManager::get<AudioScriptingInterface>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
         _webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
-        _webSurface->getSurfaceContext()->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
-        _webSurface->getSurfaceContext()->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
-        _webSurface->getSurfaceContext()->setContextProperty("Vec3", new Vec3());
-        _webSurface->getSurfaceContext()->setContextProperty("Quat", new Quat());
+        _webSurface->getSurfaceContext()->setContextProperty("fileDialogHelper", new FileDialogHelper());
         _webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
-        _webSurface->getSurfaceContext()->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
-        _webSurface->getSurfaceContext()->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("OctreeStats", DependencyManager::get<OctreeStatsProvider>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("DCModel", DependencyManager::get<DomainConnectionModel>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
+        _webSurface->getSurfaceContext()->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
+        _webSurface->getSurfaceContext()->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance());
+        _webSurface->getSurfaceContext()->setContextProperty("InputConfiguration", DependencyManager::get<InputConfiguration>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
+        _webSurface->getSurfaceContext()->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
 
-        if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") {
-            auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
-            auto flags = tabletScriptingInterface->getFlags();
+        _webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
 
-            _webSurface->getSurfaceContext()->setContextProperty("offscreenFlags", flags);
-            _webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
-            _webSurface->getSurfaceContext()->setContextProperty("Account", AccountScriptingInterface::getInstance());
-            _webSurface->getSurfaceContext()->setContextProperty("Audio", DependencyManager::get<AudioScriptingInterface>().data());
-            _webSurface->getSurfaceContext()->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
-            _webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
-            _webSurface->getSurfaceContext()->setContextProperty("fileDialogHelper", new FileDialogHelper());
-            _webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
-            _webSurface->getSurfaceContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
-            _webSurface->getSurfaceContext()->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
-            _webSurface->getSurfaceContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
-            _webSurface->getSurfaceContext()->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
-            _webSurface->getSurfaceContext()->setContextProperty("OctreeStats", DependencyManager::get<OctreeStatsProvider>().data());
-            _webSurface->getSurfaceContext()->setContextProperty("DCModel", DependencyManager::get<DomainConnectionModel>().data());
-            _webSurface->getSurfaceContext()->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
-            _webSurface->getSurfaceContext()->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
-            _webSurface->getSurfaceContext()->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
-            _webSurface->getSurfaceContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance());
-            _webSurface->getSurfaceContext()->setContextProperty("InputConfiguration", DependencyManager::get<InputConfiguration>().data());
-            _webSurface->getSurfaceContext()->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
-            _webSurface->getSurfaceContext()->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
-
-            _webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
-
-            tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface.data());
-
-            // mark the TabletProxy object as cpp ownership.
-            QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
-            _webSurface->getSurfaceContext()->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership);
-
-            // Override min fps for tablet UI, for silky smooth scrolling
-            setMaxFPS(90);
-        }
+        tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface.data());
+        // mark the TabletProxy object as cpp ownership.
+        QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
+        _webSurface->getSurfaceContext()->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership);
+        // Override min fps for tablet UI, for silky smooth scrolling
+        setMaxFPS(90);
     }
-    _webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
 }
 
 void Web3DOverlay::setMaxFPS(uint8_t maxFPS) {
@@ -594,11 +578,25 @@ QVariant Web3DOverlay::getProperty(const QString& property) {
 }
 
 void Web3DOverlay::setURL(const QString& url) {
-    _url = url;
-    if (_webSurface) {
-        AbstractViewStateInterface::instance()->postLambdaEvent([this, url] {
-            loadSourceURL();
-        });
+    if (url != _url) {
+        bool wasWebContent = isWebContent();
+        _url = url;
+        if (_webSurface) {
+            if (wasWebContent && isWebContent()) {
+                // If we're just targeting a new web URL, then switch to that without messing around
+                // with the underlying QML
+                AbstractViewStateInterface::instance()->postLambdaEvent([this, url] {
+                    _webSurface->getRootItem()->setProperty("url", _url);
+                    _webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
+                });
+            } else {
+                // If we're switching to or from web content, or between different QML content
+                // we need to destroy and rebuild the entire QML surface
+                AbstractViewStateInterface::instance()->postLambdaEvent([this, url] {
+                    rebuildWebSurface();
+                });
+            }
+        }
     }
 }
 
diff --git a/interface/src/ui/overlays/Web3DOverlay.h b/interface/src/ui/overlays/Web3DOverlay.h
index 6bd540d120..9b7be11a4a 100644
--- a/interface/src/ui/overlays/Web3DOverlay.h
+++ b/interface/src/ui/overlays/Web3DOverlay.h
@@ -31,8 +31,6 @@ public:
     Web3DOverlay(const Web3DOverlay* Web3DOverlay);
     virtual ~Web3DOverlay();
 
-    QString pickURL();
-    void loadSourceURL();
     void setMaxFPS(uint8_t maxFPS);
     virtual void render(RenderArgs* args) override;
     virtual const render::ShapeKey getShapeKey() override;
@@ -79,6 +77,10 @@ signals:
     void releaseWebSurface();
 
 private:
+    void setupQmlSurface();
+    void rebuildWebSurface();
+    bool isWebContent() const;
+
     InputMode _inputMode { Touch };
     QSharedPointer<OffscreenQmlSurface> _webSurface;
     gpu::TexturePointer _texture;
diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp
index 8ab03b60d0..4e625c2494 100644
--- a/libraries/ui/src/ui/TabletScriptingInterface.cpp
+++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp
@@ -26,6 +26,8 @@
 // FIXME move to global app properties
 const QString SYSTEM_TOOLBAR = "com.highfidelity.interface.toolbar.system";
 const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";
+const QString TabletScriptingInterface::QML = "hifi/tablet/TabletRoot.qml";
+
 
 TabletScriptingInterface::TabletScriptingInterface() {
 }
diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h
index d3590ec62e..386bce45a8 100644
--- a/libraries/ui/src/ui/TabletScriptingInterface.h
+++ b/libraries/ui/src/ui/TabletScriptingInterface.h
@@ -42,6 +42,7 @@ class TabletScriptingInterface : public QObject, public Dependency {
 public:
     TabletScriptingInterface();
     ~TabletScriptingInterface();
+    static const QString QML;
 
     void setToolbarScriptingInterface(ToolbarScriptingInterface* toolbarScriptingInterface) { _toolbarScriptingInterface = toolbarScriptingInterface; }
 
diff --git a/scripts/system/tablet-ui/tabletUI.js b/scripts/system/tablet-ui/tabletUI.js
index 9d2382b3f8..556ccb95d6 100644
--- a/scripts/system/tablet-ui/tabletUI.js
+++ b/scripts/system/tablet-ui/tabletUI.js
@@ -97,7 +97,7 @@
         checkTablet()
 
         tabletScalePercentage = getTabletScalePercentageFromSettings();
-        UIWebTablet = new WebTablet("qml/hifi/tablet/TabletRoot.qml",
+        UIWebTablet = new WebTablet("hifi/tablet/TabletRoot.qml",
                                     DEFAULT_WIDTH * (tabletScalePercentage / 100),
                                     null, activeHand, true, null, false);
         UIWebTablet.register();