diff --git a/demo.py b/demo.py
index 1781f1d49c967d1253191109d1f0fc22dab8e10e..bb1f7bfc87fb1342bb534e0ccfa5ab443c088b7e 100644
--- a/demo.py
+++ b/demo.py
@@ -11,6 +11,8 @@ import requests
 import time
 import math
 import json
+import asyncio
+import websockets
 
 NORMALIZATION_BETWEEN = (0.8, 1.2)
 LO_NORM = NORMALIZATION_BETWEEN[0]
@@ -65,7 +67,7 @@ COLOR_B_HARD = [c[1][2] for c in COLORS_FULL_SPECTRUM_HARD]
 COLORMAP = None
 COLORMAP_HARD = None
 
-
+SOCKET_URI = "ws://localhost:8765/?client_id=lib&operation="
 
 def try_and_ignore(ignore=Exception, default_value=0.0):
     """
@@ -89,7 +91,6 @@ api_content_esri = ""
 api_content_aruco = ""
 api_content_unity_png = None
 
-
 class FakeSandbox:
     """Placeholder for testing purposes"""
     def __init__(self, refresh=250):
@@ -278,15 +279,15 @@ def make_esri_and_send(depth, color, *args):
     # with open("aruco_tags.json", "w") as fp:
     #     json.dump(tags, fp)
 
+    # asyncio.run(push_height())
+    asyncio.run(pull_unity_frame())
+
     if api_content_unity_png is not None:
         cv2.resize(api_content_unity_png, (levels.shape[0], levels.shape[1]))
         im_rgb = cv2.cvtColor(api_content_unity_png, cv2.COLOR_BGR2RGB)
-        # im_rgb = cv2.flip(im_rgb, 1)
-        # im_rgb = cv2.flip(im_rgb, 0) 
-
         return im_rgb
+
     # Return value will be displayed on the beamer
-    print(f"levels {levels.shape}")
     return levels
 
 
@@ -306,7 +307,6 @@ def get_center(corner):
 def detect_aruco(frame,
                  aruco_dict=cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_4X4_50),
                  aruco_params=cv2.aruco.DetectorParameters()):
-    # output = frame.copy()
     
     #(corners, ids, rejected) = cv2.aruco.detectMarkers(frame, aruco_dict, parameters=aruco_params)
     detector = cv2.aruco.ArucoDetector(aruco_dict, aruco_params)
@@ -373,26 +373,42 @@ def rgb_to_hex(rgb):
     rgb = (r, g, b)
     return '#%02x%02x%02x' % rgb
 
-
 class ApiUnity:
     def on_get(self, req, resp):
         resp.media = api_content_esri
 
-    def on_post(self, req, resp):
-        global api_content_unity_png
-        image_data = req.bounded_stream.read()
-        api_content_unity_png = np.array(Image.open(BytesIO(image_data)))
-        print(f"FROMPOST: {api_content_unity_png.shape}")
+    # def on_post(self, req, resp):
+    #     global api_content_unity_png
+    #     image_data = req.bounded_stream.read()
+    #     api_content_unity_png = np.array(Image.open(BytesIO(image_data)))
 
-        resp.status = falcon.HTTP_200
-        resp.media = {'message': 'Data received successfully'}
+    #     print(f'received {req.params}')
+
+    #     resp.status = falcon.HTTP_200
+    #     resp.media = {'message': 'Data received successfully'}
 
 class ApiAruco:
     def on_get(self, req, resp):
         # resp.media = json.dumps(api_content_aruco)
         resp.media = api_content_aruco
 
-def main():    
+async def push_height():
+    global api_content_esri
+
+    # Size of map is 4993453 bytes
+
+    async with websockets.connect(SOCKET_URI + "push") as websocket:
+        await websocket.send(api_content_esri)
+        response = await websocket.recv()
+
+async def pull_unity_frame():
+    global api_content_unity_png
+    async with websockets.connect(SOCKET_URI + "pull") as websocket:
+        await websocket.send("Request frame")
+        response = await websocket.recv()
+        api_content_unity_png = np.array(Image.open(BytesIO(response)))
+
+def main():
     arg_colors = ""
     if arg_colors != "":
         colours = []
@@ -416,7 +432,7 @@ def main():
     # COLORMAP_HARD = create_colormap(create_hard_colors(colours))
 
     LINE_COLORS = [0,0,0]
-    box = Sandbox(refresh=1000)
+    box = Sandbox(refresh=50)
     box.verbosity = 5
     box.init()
     box.on_frame = make_esri_and_send
@@ -433,13 +449,11 @@ app.add_route('/aruco', ApiAruco())
 
 class ApiThread(Thread):
     def run(self):
-        print("run")
         with make_server('', 8000, app) as httpd:
             print('Serving on port 8000...')
 
             # Serve until process is killed
             httpd.serve_forever()
 
-
 ApiThread().start()
 main()
diff --git a/socketServer.py b/socketServer.py
new file mode 100644
index 0000000000000000000000000000000000000000..d49e3fe42c4b623d1dab4bb2b170fca63f9c02d5
--- /dev/null
+++ b/socketServer.py
@@ -0,0 +1,58 @@
+import asyncio
+import websockets
+import urllib.parse
+
+UNITY_ID = "unity"
+LIB_ID = "lib"
+
+PUSH = "push"
+PULL = "pull"
+
+unity_frame = None
+height_map = None
+
+async def echo(websocket):
+    global unity_frame, height_map
+
+    query_params = urllib.parse.parse_qs(urllib.parse.urlparse(websocket.request.path).query)
+    client_id = query_params.get('client_id', ['Unknown'])[0]
+    operation = query_params.get('operation', ['Unknown'])[0]
+
+    try:
+        async for message in websocket:
+            print(f"Received: from {client_id} with operation {operation}")
+
+            # Unity
+            if client_id == UNITY_ID:
+                if operation == PUSH:
+                    unity_frame = message
+                    await websocket.send("200: OK")
+                elif operation == PULL:
+                    await websocket.send(height_map)
+                else:
+                    await websocket.send("400: Bad Request")
+
+            # Lib
+            elif client_id == LIB_ID:
+                if operation == PUSH:
+                    height_map = message
+                elif operation == PULL:
+                    await websocket.send(unity_frame)
+                else:
+                    await websocket.send("400: Bad Request")
+
+            # Bad url ?
+            else:
+                await websocket.send("403: Unable to identify you")
+            
+    except websockets.exceptions.ConnectionClosed as e:
+        print(f"Client disconnected: {e.code}")
+    finally:
+        print("Connection closed")
+
+async def main():
+    async with websockets.serve(echo, "localhost", 8765, max_size=10**7):
+        print("WebSocket server running on ws://localhost:8765")
+        await asyncio.Future()  # Run the server indefinitely
+
+asyncio.run(main())