diff --git a/package-lock.json b/package-lock.json
index 2be1cab..d05d659 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
       "name": "nq-client",
       "version": "0.0.0",
       "dependencies": {
+        "@vueuse/core": "^10.9.0",
         "pinia": "^2.1.7",
         "vue": "^3.4.21"
       },
@@ -1647,6 +1648,11 @@
       "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
       "dev": true
     },
+    "node_modules/@types/web-bluetooth": {
+      "version": "0.0.20",
+      "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
+      "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="
+    },
     "node_modules/@types/ws": {
       "version": "8.5.10",
       "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz",
@@ -2282,6 +2288,89 @@
       "integrity": "sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==",
       "dev": true
     },
+    "node_modules/@vueuse/core": {
+      "version": "10.9.0",
+      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.9.0.tgz",
+      "integrity": "sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==",
+      "dependencies": {
+        "@types/web-bluetooth": "^0.0.20",
+        "@vueuse/metadata": "10.9.0",
+        "@vueuse/shared": "10.9.0",
+        "vue-demi": ">=0.14.7"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/@vueuse/core/node_modules/vue-demi": {
+      "version": "0.14.7",
+      "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
+      "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
+      "hasInstallScript": true,
+      "bin": {
+        "vue-demi-fix": "bin/vue-demi-fix.js",
+        "vue-demi-switch": "bin/vue-demi-switch.js"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "@vue/composition-api": "^1.0.0-rc.1",
+        "vue": "^3.0.0-0 || ^2.6.0"
+      },
+      "peerDependenciesMeta": {
+        "@vue/composition-api": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vueuse/metadata": {
+      "version": "10.9.0",
+      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.9.0.tgz",
+      "integrity": "sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==",
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/@vueuse/shared": {
+      "version": "10.9.0",
+      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.9.0.tgz",
+      "integrity": "sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==",
+      "dependencies": {
+        "vue-demi": ">=0.14.7"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/@vueuse/shared/node_modules/vue-demi": {
+      "version": "0.14.7",
+      "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
+      "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
+      "hasInstallScript": true,
+      "bin": {
+        "vue-demi-fix": "bin/vue-demi-fix.js",
+        "vue-demi-switch": "bin/vue-demi-switch.js"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "@vue/composition-api": "^1.0.0-rc.1",
+        "vue": "^3.0.0-0 || ^2.6.0"
+      },
+      "peerDependenciesMeta": {
+        "@vue/composition-api": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/abbrev": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
diff --git a/package.json b/package.json
index 6ae9a2b..a487a22 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
     "format": "prettier --write src/"
   },
   "dependencies": {
+    "@vueuse/core": "^10.9.0",
     "pinia": "^2.1.7",
     "vue": "^3.4.21"
   },
diff --git a/src/App.vue b/src/App.vue
index 0dfe2f8..f46cc09 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -5,4 +5,16 @@
 <script setup lang="ts">
 import Game from '@/components/Game.vue'
 import Login from '@/components/screens/Login.vue'
+import { useWebSocket } from '@vueuse/core'
+import config from '@/config'
+
+const { status, data, close } = useWebSocket(config.websocket_url, {
+  autoReconnect: {
+    retries: 3,
+    delay: 1000,
+    onFailed() {
+      alert('Failed to connect WebSocket after 3 retries')
+    },
+  },
+})
 </script>
\ No newline at end of file