diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index fa8a2154c6bb2efea0948737b79378de87364115..cc63b5227e9c58f89c87d64c2190c6f09adb1550 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.qtdesignviewer"
-    android:installLocation="auto" android:versionCode="19" android:versionName="1.2">
+    android:installLocation="auto" android:versionCode="20" android:versionName="1.2">
     <!-- %%INSERT_PERMISSIONS -->
     <!-- %%INSERT_FEATURES -->
     <supports-screens android:anyDensity="true" android:largeScreens="true"
diff --git a/src/backend.cpp b/src/backend.cpp
index 5562cc9cf4594b3e1ffc502f2dd5711dbcb30fa1..b198893489d8cee2aa20635cca32734b87f6b4ad 100644
--- a/src/backend.cpp
+++ b/src/backend.cpp
@@ -26,8 +26,6 @@
 #include "backend.h"
 #include "qapplication.h"
 
-#if !defined(Q_OS_WASM)
-
 #include <QDesktopServices>
 #include <QFileInfo>
 #include <QJsonArray>
@@ -40,7 +38,7 @@ Backend::Backend(QObject *parent)
     : QObject(parent)
 {
     // This will allow us to open the app with the QR code
-    QDesktopServices::setUrlHandler("qtdesignviewer", this, "registerUser");
+    QDesktopServices::setUrlHandler("qtdesignviewer", this, "parseDesignViewerUrl");
 }
 
 void Backend::initialize()
@@ -74,11 +72,6 @@ void Backend::initialize()
         updateUserProjectList();
     }
 
-    connect(&m_serviceConnector,
-            &ServiceConnector::downloadProgress,
-            this,
-            &Backend::downloadProgress);
-
     qDebug("Initialization complete");
 }
 
@@ -94,15 +87,17 @@ void Backend::initializeProjectManager()
     if (m_projectManager)
         return;
 
-    qDebug() << "Initializing Project Manager";
     m_projectManager.reset(new ProjectManager);
     connect(m_projectManager.data(), &ProjectManager::closingProject, this, [&] {
         emit popupClose();
-        qDebug() << "Project Manager is closing";
         m_projectManager.reset();
     });
 
-    qDebug() << "Project Manager is initialized";
+    m_serviceConnector.reset(new ServiceConnector);
+    connect(m_serviceConnector.data(),
+            &ServiceConnector::downloadProgress,
+            this,
+            &Backend::downloadProgress);
 }
 
 bool Backend::connectDesignStudio()
@@ -204,7 +199,7 @@ void Backend::runDemoProject(const QString &projectName)
         updatePopup("Downloading demo project...", false);
 
         const QString url = "https://designviewer.qt.io/qmlprojects/" + projectName + ".qmlrc";
-        QByteArray project = m_serviceConnector.fetchProject(url);
+        QByteArray project = m_serviceConnector->fetchProject(url);
         qDebug() << "Demo project is not cached. Trying to download from " << url << " ...";
 
         updatePopup("Caching demo project...");
@@ -239,15 +234,17 @@ void Backend::clearDemoCaches()
     emit popupClose();
 }
 
-void Backend::runUserProject(const QString &url)
+void Backend::runUserProject(const QString &projectName)
 {
     initializeProjectManager();
     updatePopup("Running user project");
     emit popupOpen();
 
+    qDebug() << "Running user project:" << projectName;
+
     qDebug("Checking if project is cached. Getting list of available projects...");
-    const QJsonArray projectList = m_serviceConnector.fetchUserProjectList(m_userHash);
-    const QString projectName = QFileInfo(url).baseName();
+    const QJsonArray projectList = m_serviceConnector->fetchUserProjectList(m_userHash);
+
     QString projectLastModified;
     QString projectId;
     QJsonObject projectInfo;
@@ -263,7 +260,7 @@ void Backend::runUserProject(const QString &url)
     if (!projectCached) {
         qDebug("Project is not cached. Downloading...");
         updatePopup("Project is not cached. Downloading...", false);
-        QByteArray projectData = m_serviceConnector.fetchProject(url);
+        QByteArray projectData = m_serviceConnector->fetchUserProject(m_userHash, projectName);
 
         updatePopup("Caching user project...");
         if (!m_projectManager->cacheProject(projectData, projectInfo)) {
@@ -285,6 +282,30 @@ void Backend::runUserProject(const QString &url)
     emit popupClose();
 }
 
+void Backend::runOnlineProject(const QString &url)
+{
+    initializeProjectManager();
+    emit popupOpen();
+    updatePopup("Downloading...", false);
+    QByteArray projectData = m_serviceConnector->fetchProject(url);
+    if (projectData.isEmpty()) {
+        qCritical() << "Could not download project. Please check the logs for more information.";
+        return;
+    }
+
+    updatePopup("Unpacking project...");
+    QString projectPath = m_projectManager->unpackProject(projectData);
+    updatePopup("Running project...");
+
+    if (!m_projectManager->runProject(projectPath))
+        qCritical() << "Could not run project. Please check the logs for more information.";
+    else {
+        m_projectManager->showAppWindow();
+    }
+
+    emit popupClose();
+}
+
 void Backend::registerUser(const QUrl &url)
 {
     const QString userHash = url.toString().remove("qtdesignviewer://");
@@ -298,7 +319,8 @@ void Backend::registerUser(const QUrl &url)
 void Backend::updateUserProjectList()
 {
     qDebug() << "Fetching available project list for user: " << m_userHash;
-    QJsonArray projectList = m_serviceConnector.fetchUserProjectList(m_userHash);
+    m_serviceConnector.reset(new ServiceConnector);
+    QJsonArray projectList = m_serviceConnector->fetchUserProjectList(m_userHash);
 
     m_projectList.clear();
     qDebug("List of available projects fetched:");
@@ -310,4 +332,23 @@ void Backend::updateUserProjectList()
     emit projectListChanged();
 }
 
-#endif // !defined(Q_OS_WASM)
+void Backend::parseDesignViewerUrl(const QUrl &url)
+{
+    QString urlData = url.toString().remove("qtdesignviewer://");
+    // urlData could be either a direct url to the project or a user hash
+    // If it is a user hash, we register the user and fetch the project list
+    // If it is a project url, we submit the url to the text field
+    // sample url: qtdesignviewer://https://<url>/<project_name>.qmlrc
+    // sample user hash: qtdesignviewer://17e8907b3b84029384hs8djshdu38476
+    if (urlData.isEmpty())
+        return;
+    else if (urlData.startsWith("https//")) {
+        urlData.replace("https//", "https://");
+        emit urlUpdated(urlData);
+    } else if (urlData.startsWith("https://")) {
+        emit urlUpdated(urlData);
+    } else {
+        qDebug() << "Registering user from QR code";
+        registerUser(url);
+    }
+}
diff --git a/src/backend.h b/src/backend.h
index 13aa6a5d71d7c126c680eb5643b9447a110652cf..d3e99d3d60f37e01e546a854e121422cb30b6d0b 100644
--- a/src/backend.h
+++ b/src/backend.h
@@ -57,7 +57,7 @@ private:
 
     // Other members
     QString m_userHash;
-    ServiceConnector m_serviceConnector;
+    QScopedPointer<ServiceConnector> m_serviceConnector;
     QScopedPointer<ProjectManager> m_projectManager;
     QScopedPointer<DesignStudioConnector> m_designStudioConnector;
     QThread m_dsConnectorThread;
@@ -78,15 +78,19 @@ signals:
     void popupClose();
     void userRegistered();
     void networkUpdated(QString);
+    void urlUpdated(QString);
 
 public slots:
-    void runUserProject(const QString &url);
+    void runOnlineProject(const QString &url);
+    void runUserProject(const QString &projectName);
     void runDemoProject(const QString &projectName);
     void clearDemoCaches();
-    void registerUser(const QUrl &url);
+
     bool connectDesignStudio();
     void disconnectDesignStudio();
 
+    void parseDesignViewerUrl(const QUrl &url);
+    void registerUser(const QUrl &url);
 private slots:
     void initializeProjectManager();
 };
diff --git a/src/main.cpp b/src/main.cpp
index 678f21455ad3514463ae6cc022809371cc1659ec..24974a06aeafbd3f0cec030801f785659fceaf6d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -35,13 +35,13 @@ static QString appLogs;
 
 void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
 {
+    QString logPrefix, logSuffix, newLog;
+
     QByteArray localMsg = msg.toLocal8Bit();
     const char *file = context.file ? context.file : "";
     const char *function = context.function ? context.function : "";
-    QString logPrefix, logSuffix, newLog;
-    QMessageBox msgBox(QMessageBox::Critical, "Critical:", msg, QMessageBox::Ok);
-    switch (type)
-    {
+
+    switch (type) {
     case QtDebugMsg:
         logPrefix = QStringLiteral("Debug: ");
         break;
@@ -53,7 +53,6 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt
         break;
     case QtCriticalMsg:
         logPrefix = QStringLiteral("Critical: ");
-        msgBox.exec();
         break;
     case QtFatalMsg:
         logPrefix = QStringLiteral("Fatal: ");
@@ -64,16 +63,13 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt
     newLog += logPrefix + localMsg + logSuffix + "\n";
     __android_log_print(ANDROID_LOG_DEBUG, "Qt_UI_Viewer", "%s", qPrintable(newLog));
 
-    static int logCounter = 0;
-    if (logCounter++ == 100) {
-        // remove the first line
-        int index = appLogs.indexOf('\n');
-        if (index > 0)
-            appLogs.remove(0, index + 1);
-        logCounter = 99;
+    // only show critical and fatal messages in the UI
+    if (type == QtCriticalMsg || type == QtFatalMsg) {
+        QMessageBox msgBox{QMessageBox::Critical, "Critical:", msg, QMessageBox::Ok};
+        msgBox.exec();
+        if (backend)
+            backend->setLogs(appLogs += newLog);
     }
-    if (backend)
-        backend->setLogs(appLogs += newLog);
 }
 
 int main(int argc, char *argv[])
diff --git a/src/projectManager.cpp b/src/projectManager.cpp
index 090b8de4489d09e233cae2f01eddd95031f1803e..1501a2f7fa40c2d479aa4f7311a3e90a964cd671 100644
--- a/src/projectManager.cpp
+++ b/src/projectManager.cpp
@@ -62,6 +62,25 @@ ProjectManager::ProjectManager(QObject *parent)
     }
 }
 
+ProjectManager::~ProjectManager()
+{
+    cleanupResources();
+    qDebug() << "ProjectManager destroyed.";
+}
+
+void ProjectManager::cleanupResources()
+{
+    const uchar *data;
+    if (m_projectData.size()) {
+        qDebug() << "Unregistering the previous data from QRC system. Path: " << m_projectPath
+                 << " Size: " << m_projectData.size() << " bytes.";
+        data = reinterpret_cast<const uchar *>(m_projectData.data());
+        if (!QResource::unregisterResource(data, m_projectPath)) {
+            qCritical("Cannot unregister the previous resource data.");
+        }
+    }
+}
+
 QString ProjectManager::unpackProject(const QByteArray &project, bool extractZip)
 {
     QTemporaryDir tempDir("qmlprojector");
@@ -85,17 +104,10 @@ QString ProjectManager::unpackProject(const QByteArray &project, bool extractZip
         if (extractZip)
             qDebug("File could not be extracted. Trying to open it as a resource file.");
 
-        const uchar *data;
-        if (m_projectData.size()) {
-            qDebug() << "Unregistering the previous data from QRC system. Path: " << m_projectPath
-                     << " Size: " << m_projectData.size() << " bytes.";
-            data = reinterpret_cast<const uchar *>(m_projectData.data());
-            if (!QResource::unregisterResource(data, m_projectPath)) {
-                qCritical("Cannot unregister the previous resource data.");
-            }
-        }
+        cleanupResources();
 
         m_projectData = project;
+        const uchar *data;
         data = reinterpret_cast<const uchar *>(m_projectData.data());
         qDebug() << "Registering resource data. Size: " << m_projectData.size();
 
diff --git a/src/projectManager.h b/src/projectManager.h
index 6bfbf141bfb047531abd498fb4d4be181ed678a6..b49a275e7453d72021a02fa4d6cba4ce9371bb4d 100644
--- a/src/projectManager.h
+++ b/src/projectManager.h
@@ -38,6 +38,7 @@ class ProjectManager : public QObject
     Q_OBJECT
 public:
     explicit ProjectManager(QObject *parent = nullptr);
+    ~ProjectManager();
 
     QString unpackProject(const QByteArray &project, bool extractZip = false);
     bool runProject(const QString &projectPath);
@@ -78,6 +79,7 @@ private:
 
     void parseQmlProjectFile(const QString &fileName, QString *mainFile, QStringList *importPaths);
     void cacheProject(const QString &projectName, const QString &projectPath);
+    void cleanupResources();
 
 signals:
     void closingProject();
diff --git a/src/serviceConnector.cpp b/src/serviceConnector.cpp
index fe95e0565a49a3085998a4d08c60c63ee55f6419..eb7e4aaaa6c65d880c3ab658636af1395e696c5e 100644
--- a/src/serviceConnector.cpp
+++ b/src/serviceConnector.cpp
@@ -31,7 +31,7 @@
 #include <QJsonDocument>
 #include <QJsonObject>
 
-QSharedPointer<QNetworkReply> ServiceConnector::fetchResource(const QString &url)
+QByteArray ServiceConnector::fetchResource(const QString &url)
 {
     qDebug() << "Fetching resource from" << url;
 
@@ -64,7 +64,7 @@ QSharedPointer<QNetworkReply> ServiceConnector::fetchResource(const QString &url
     else
         qDebug() << "Resource fetched successfully";
 
-    return reply;
+    return reply->readAll();
 }
 
 QByteArray ServiceConnector::fetchProject(const QString &url)
@@ -76,26 +76,25 @@ QByteArray ServiceConnector::fetchProject(const QString &url)
         projectUrl.prepend("https://designviewer.qt.io/qmlprojects/");
     }
 
-    auto reply = fetchResource(projectUrl);
-    if (reply->error() != QNetworkReply::NoError)
-    {
-        qCritical("Could not fetch project");
-        return QByteArray();
-    }
+    return fetchResource(projectUrl);
+}
 
-    return reply->readAll();
+QByteArray ServiceConnector::fetchUserProject(const QString &userHash, const QString &projectName)
+{
+    const QString projectUrl = "https://designviewer.qt.io/qmlprojects/" + userHash + "/"
+                               + projectName + ".qmlrc";
+    return fetchResource(projectUrl);
 }
 
 QJsonArray ServiceConnector::fetchUserProjectList(const QString &userHash)
 {
     auto reply = fetchResource("https://designviewer.qt.io/api/v1/qmlrc/list/" + userHash + "?key=818815");
-    if (reply->error() != QNetworkReply::NoError)
-    {
+    if (reply.size() == 0) {
         qCritical("Could not fetch available project list");
         return QJsonArray();
     }
 
-    QJsonArray projectList = QJsonDocument::fromJson(reply->readAll())
+    QJsonArray projectList = QJsonDocument::fromJson(reply)
                                  .object()
                                  .value("data")
                                  .toObject()
diff --git a/src/serviceConnector.h b/src/serviceConnector.h
index b552806d758fb9651861c24f7a671f45a3349b95..cd9482329aee1d397445d90489a58cd329ab291a 100644
--- a/src/serviceConnector.h
+++ b/src/serviceConnector.h
@@ -34,11 +34,12 @@ class ServiceConnector : public QObject
     Q_OBJECT
 public:
     QByteArray fetchProject(const QString &url);
+    QByteArray fetchUserProject(const QString &userHash, const QString &projectName);
     QJsonArray fetchUserProjectList(const QString &userHash);
 
 private:
     QNetworkAccessManager m_manager;
-    QSharedPointer<QNetworkReply> fetchResource(const QString &url);
+    QByteArray fetchResource(const QString &url);
 
 signals:
     void downloadProgress(float percentage);
diff --git a/ui/HomePage.qml b/ui/HomePage.qml
index b57576675cb2a560e723fff8f821c93622b37387..4ed0c0264c06913eb29206fa48367886d0433700 100644
--- a/ui/HomePage.qml
+++ b/ui/HomePage.qml
@@ -47,32 +47,64 @@ Item {
             Layout.fillWidth: true
         }
 
-        ComboBox {
-            id: projectList
+        ColumnLayout {
+            id: column2
             Layout.fillWidth: true
-            onCurrentIndexChanged: {
-                urlTextField.text = "https://designviewer.qt.io/qmlprojects/"
-                        + backend.userHash + "/"
-                        + textAt(currentIndex)
-                        + ".qmlrc"
-                displayText = textAt(currentIndex)
-            }
-            onModelChanged: {
-                if (model.count > 0) {
-                    currentIndex = 0
+            ComboBox {
+                id: projectList
+                Layout.fillWidth: true
+                onCurrentIndexChanged: {
+                    displayText = textAt(currentIndex)
+                    downloadUserProject.enabled = true
                 }
+                onModelChanged: {
+                    if (model.count > 0) {
+                        currentIndex = 0
+                    }
+                }
+                model: backend.projectList
+                down: false
+                displayText: "Select project..."
+                currentIndex: -1
+                Layout.preferredHeight: 50
+            }
+
+            Button {
+                id: downloadUserProject
+                text: qsTr("Run Project")
+                onClicked: backend.runUserProject(projectList.currentText)
+                enabled: backend.userHash !== ''
+                Layout.fillWidth: true
+                Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
             }
-            model: backend.projectList
-            down: false
-            displayText: "Select project..."
-            currentIndex: -1
-            Layout.preferredHeight: 50
         }
 
 
+
+        Item {
+            id: item3
+            Layout.fillHeight: true
+            Layout.fillWidth: true
+            Layout.preferredHeight: 10
+            Layout.preferredWidth: 10
+        }
+
+
+
         ColumnLayout {
             id: column
             Layout.fillWidth: true
+
+            Text {
+                id: downloadInstructions
+                text: qsTr("Enter project URL and then click the button below")
+                font.pixelSize: 12
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+                wrapMode: Text.WordWrap
+                Layout.fillWidth: true
+            }
+
             TextField {
                 id: urlTextField
                 horizontalAlignment: Text.AlignHCenter
@@ -85,26 +117,20 @@ Item {
                 id: rowLayout
                 Button {
                     id: downloadButton
-                    text: qsTr("Download and Run")
-                    onClicked: backend.runUserProject(urlTextField.text)
+                    text: qsTr("Download and Run Project")
+                    onClicked: backend.runOnlineProject(urlTextField.text)
                     enabled: urlTextField.text !== ''
                     Layout.fillWidth: true
                     Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
                 }
             }
-        }
 
-
-        Item {
-            id: item1
-            Layout.fillHeight: true
-            Layout.fillWidth: true
-            Layout.preferredHeight: 10
-            Layout.preferredWidth: 10
+            Connections {
+                target: backend
+                function onUrlUpdated(newUrl){
+                    urlTextField.text = newUrl;
+                }
+            }
         }
-
-
-
-
     }
 }