diff --git a/README.md b/README.md
index a4ce2c4..7faaa9d 100644
--- a/README.md
+++ b/README.md
@@ -170,7 +170,8 @@ import pydase
 
 # Replace the hostname and port with the IP address and the port of the machine where 
 # the service is running, respectively
-client_proxy = pydase.Client(hostname="<ip_addr>", port=8001).proxy
+client_proxy = pydase.Client(url="ws://<ip_addr>:<service_port>").proxy
+# client_proxy = pydase.Client(url="wss://your-domain.ch").proxy  # if your service uses ssl-encryption
 
 # After the connection, interact with the service attributes as if they were local
 client_proxy.voltage = 5.0
@@ -195,7 +196,8 @@ import pydase
 
 class MyService(pydase.DataService):
     # Initialize the client without blocking the constructor
-    proxy = pydase.Client(hostname="<ip_addr>", port=8001, block_until_connected=False).proxy
+    proxy = pydase.Client(url="ws://<ip_addr>:<service_port>", block_until_connected=False).proxy
+    # proxy = pydase.Client(url="wss://your-domain.ch", block_until_connected=False).proxy  # communicating with ssl-encrypted service
 
 if __name__ == "__main__":
     service = MyService()
diff --git a/docs/user-guide/interaction/Python Client.md b/docs/user-guide/interaction/Python Client.md
index ea844f2..e41c43c 100644
--- a/docs/user-guide/interaction/Python Client.md	
+++ b/docs/user-guide/interaction/Python Client.md	
@@ -5,9 +5,10 @@ You can connect to the service using the `pydase.Client`. Below is an example of
 ```python
 import pydase
 
-# Replace the hostname and port with the IP address and the port of the machine 
-# where the service is running, respectively
-client_proxy = pydase.Client(hostname="<ip_addr>", port=8001).proxy
+# Replace the hostname and port with the IP address and the port of the machine where 
+# the service is running, respectively
+client_proxy = pydase.Client(url="ws://<ip_addr>:<service_port>").proxy
+# client_proxy = pydase.Client(url="wss://your-domain.ch").proxy  # if your service uses ssl-encryption
 
 # Interact with the service attributes as if they were local
 client_proxy.voltage = 5.0
@@ -32,7 +33,8 @@ import pydase
 
 class MyService(pydase.DataService):
     # Initialize the client without blocking the constructor
-    proxy = pydase.Client(hostname="<ip_addr>", port=8001, block_until_connected=False).proxy
+    proxy = pydase.Client(url="ws://<ip_addr>:<service_port>", block_until_connected=False).proxy
+    # proxy = pydase.Client(url="wss://your-domain.ch", block_until_connected=False).proxy  # communicating with ssl-encrypted service
 
 if __name__ == "__main__":
     service = MyService()
diff --git a/pyproject.toml b/pyproject.toml
index e621311..a881a33 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "pydase"
-version = "0.8.5"
+version = "0.9.0"
 description = "A flexible and robust Python library for creating, managing, and interacting with data services, with built-in support for web and RPC servers, and customizable features for diverse use cases."
 authors = ["Mose Mueller <mosmuell@ethz.ch>"]
 readme = "README.md"
diff --git a/src/pydase/client/client.py b/src/pydase/client/client.py
index 537a628..17b1c6b 100644
--- a/src/pydase/client/client.py
+++ b/src/pydase/client/client.py
@@ -80,12 +80,12 @@ class Client:
             if it were local.
 
     Args:
-        hostname (str):
-            Hostname of the exposed service this client attempts to connect to.
-            Default is "localhost".
-        port (int):
-            Port of the exposed service this client attempts to connect on.
-            Default is 8001.
+        url (str):
+            The URL of the pydase Socket.IO server. This should always contain the
+            protocol and the hostname.
+            Examples:
+                - wss://my-service.example.com  # for secure connections, use wss
+                - ws://localhost:8001
         block_until_connected (bool):
             If set to True, the constructor will block until the connection to the
             service has been established. This is useful for ensuring the client is
@@ -94,12 +94,11 @@ class Client:
 
     def __init__(
         self,
-        hostname: str,
-        port: int,
+        *,
+        url: str,
         block_until_connected: bool = True,
     ):
-        self._hostname = hostname
-        self._port = port
+        self._url = url
         self._sio = socketio.AsyncClient()
         self._loop = asyncio.new_event_loop()
         self.proxy = ProxyClass(sio_client=self._sio, loop=self._loop)
@@ -107,29 +106,41 @@ class Client:
             target=asyncio_loop_thread, args=(self._loop,), daemon=True
         )
         self._thread.start()
+        self.connect(block_until_connected=block_until_connected)
+
+    def connect(self, block_until_connected: bool = True) -> None:
         connection_future = asyncio.run_coroutine_threadsafe(
             self._connect(), self._loop
         )
         if block_until_connected:
             connection_future.result()
 
+    def disconnect(self) -> None:
+        connection_future = asyncio.run_coroutine_threadsafe(
+            self._disconnect(), self._loop
+        )
+        connection_future.result()
+
     async def _connect(self) -> None:
-        logger.debug("Connecting to server '%s:%s' ...", self._hostname, self._port)
+        logger.debug("Connecting to server '%s' ...", self._url)
         await self._setup_events()
         await self._sio.connect(
-            f"ws://{self._hostname}:{self._port}",
+            self._url,
             socketio_path="/ws/socket.io",
             transports=["websocket"],
             retry=True,
         )
 
+    async def _disconnect(self) -> None:
+        await self._sio.disconnect()
+
     async def _setup_events(self) -> None:
         self._sio.on("connect", self._handle_connect)
         self._sio.on("disconnect", self._handle_disconnect)
         self._sio.on("notify", self._handle_update)
 
     async def _handle_connect(self) -> None:
-        logger.debug("Connected to '%s:%s' ...", self._hostname, self._port)
+        logger.debug("Connected to '%s' ...", self._url)
         serialized_object = cast(
             SerializedDataService, await self._sio.call("service_serialization")
         )
@@ -141,7 +152,7 @@ class Client:
         self.proxy._connected = True
 
     async def _handle_disconnect(self) -> None:
-        logger.debug("Disconnected from '%s:%s' ...", self._hostname, self._port)
+        logger.debug("Disconnected from '%s' ...", self._url)
         self.proxy._connected = False
 
     async def _handle_update(self, data: NotifyDict) -> None:
diff --git a/tests/client/test_client.py b/tests/client/test_client.py
index 7a66bb2..27c2cd0 100644
--- a/tests/client/test_client.py
+++ b/tests/client/test_client.py
@@ -45,7 +45,7 @@ def pydase_client() -> Generator[pydase.Client, None, Any]:
     thread = threading.Thread(target=server.run, daemon=True)
     thread.start()
 
-    client = pydase.Client(hostname="localhost", port=9999)
+    client = pydase.Client(url="ws://localhost:9999")
 
     yield client