diff --git a/src/open/ClientView.js b/src/open/ClientView.js
index 76c73e9f6626c8dff5b580bc2f54c4f95d3a8f78..99bbf97d81eed6f154a9798c6e72d34f2d3538c9 100644
--- a/src/open/ClientView.js
+++ b/src/open/ClientView.js
@@ -82,8 +82,8 @@ class InstallClientView extends TemplateView {
                 className: "copy",
                 title: "Copy instructions",
                 "aria-label": "Copy instructions",
-                onClick: evt => {
-                    if (copy(vm.copyString, copyButton.parentElement)) {
+                onClick: async (evt) => {
+                    if (await copy(vm.copyString, copyButton.parentElement)) {
                         copyButton.className = "tick";
                         setTimeout(() => {
                             copyButton.className = "copy";
diff --git a/src/open/ClientViewModel.js b/src/open/ClientViewModel.js
index 2cd724498c3310bb0b8970a025d1a007b53ec3bd..c00bab84a2d2935a0e1e9a20af005563a616d8d2 100644
--- a/src/open/ClientViewModel.js
+++ b/src/open/ClientViewModel.js
@@ -16,7 +16,7 @@ limitations under the License.
 
 import {isWebPlatform, isDesktopPlatform, Platform} from "../Platform.js";
 import {ViewModel} from "../utils/ViewModel.js";
-import {IdentifierKind} from "../Link.js";
+import { copy } from "../utils/copy.js";
 
 function getMatchingPlatforms(client, supportedPlatforms) {
     const clientPlatforms = client.platforms;
@@ -51,32 +51,37 @@ export class ClientViewModel extends ViewModel {
         this._showOpen = this.openActions.length && !this._clientCanIntercept;
     }
 
+    _onDeepLinkClicked = async () => {
+        await copy(this.proposedDeepLink);
+        this._pickClient(this._client);
+        this.preferences.setClient(this._client.id, this._proposedPlatform);
+        // only show install screen if we tried to open a native deeplink
+        if (this._showOpen && this._proposedPlatform === this._nativePlatform) {
+            this._showOpen = false;
+            this.emitChange();
+        }
+    }
+
     // these are only shown in the open stage
     _createOpenActions() {
         const hasPreferredWebInstance = this.hasPreferredWebInstance;
-        let deepLinkLabel = "Continue";
+        this.deepLinkLabel = "Continue";
         if (hasPreferredWebInstance) {
             if (this._proposedPlatform === this._nativePlatform) {
-                deepLinkLabel = "Open in app";
+                this.deepLinkLabel = "Open in app";
             } else {
-                deepLinkLabel = `Open on ${this._client.getPreferredWebInstance(this._link)}`;
+                this.deepLinkLabel = `Open on ${this._client.getPreferredWebInstance(this._link)}`;
             }
         }
         const actions = [];
-        const proposedDeepLink = this._client.getDeepLink(this._proposedPlatform, this._link);
-        if (proposedDeepLink) {
+        this.proposedDeepLink = this._client.getDeepLink(this._proposedPlatform, this._link);
+        if (this.proposedDeepLink) {
             actions.push({
-                label: deepLinkLabel,
-                url: proposedDeepLink,
+                label: this.deepLinkLabel,
+                url: this.proposedDeepLink,
                 primary: true,
-                activated: () => {
-                    this._pickClient(this._client);
-                    this.preferences.setClient(this._client.id, this._proposedPlatform);
-                    // only show install screen if we tried to open a native deeplink
-                    if (this._showOpen && this._proposedPlatform === this._nativePlatform) {
-                        this._showOpen = false;
-                        this.emitChange();
-                    }
+                activated: async () => {
+                    this._onDeepLinkClicked();
                 },
             });
         }
@@ -105,6 +110,18 @@ export class ClientViewModel extends ViewModel {
                     activated: () => this.preferences.setClient(this._client.id, this._nativePlatform),
                 };
             });
+
+            if (!this._webPlatform && this.proposedDeepLink) {
+                actions.push({
+                    label: this.deepLinkLabel,
+                    url: this.proposedDeepLink,
+                    primary: true,
+                    activated: async () => {
+                        this._onDeepLinkClicked();
+                    },
+                })
+            }
+
             actions.push(...nativeActions);
         }
         if (this._webPlatform) {
diff --git a/src/utils/copy.js b/src/utils/copy.js
index c417bfdae73762ff61471d900bfe7984a664ea48..7da62796cd18fb5c33c2d8053e8d44b8d85b5140 100644
--- a/src/utils/copy.js
+++ b/src/utils/copy.js
@@ -1,5 +1,5 @@
 /*
-Copyright 2020 The Matrix.org Foundation C.I.C.
+Copyright 2020 - 2022 The Matrix.org Foundation C.I.C.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -22,14 +22,21 @@ function selectNode(node) {
     selection.addRange(range);
 }
 
-export function copy(text, parent) {
-    const span = document.createElement("span");
-    span.innerText = text;
-    parent.appendChild(span);
-    selectNode(span);
-    const result = document.execCommand("copy");
-    parent.removeChild(span);
-    return result;
+export async function copy(text, parent) {
+    if ("clipboard" in navigator) {
+        const type = "text/plain";
+        const blob = new Blob([text], { type });
+        const data = [new ClipboardItem({ [type]: blob })];
+        return navigator.clipboard.write(data);
+    } else {
+        const span = document.createElement("span");
+        span.innerText = text;
+        parent.appendChild(span);
+        selectNode(span);
+        const result = document.execCommand("copy");
+        parent.removeChild(span);
+        return result;
+    }
 }
 
 export function copyButton(t, getCopyText, label, classNames) {