diff --git a/docs/_images/extension/websocket/lucee-admin-extension.png b/docs/_images/extension/websocket/lucee-admin-extension.png
new file mode 100644
index 000000000..246680a67
Binary files /dev/null and b/docs/_images/extension/websocket/lucee-admin-extension.png differ
diff --git a/docs/_images/extension/websocket/websocket-lex.png b/docs/_images/extension/websocket/websocket-lex.png
new file mode 100644
index 000000000..5d1ed178a
Binary files /dev/null and b/docs/_images/extension/websocket/websocket-lex.png differ
diff --git a/docs/_images/extension/websocket/websocketInfo.png b/docs/_images/extension/websocket/websocketInfo.png
new file mode 100644
index 000000000..b075f008c
Binary files /dev/null and b/docs/_images/extension/websocket/websocketInfo.png differ
diff --git a/docs/recipes/extension-websocket.md b/docs/recipes/extension-websocket.md
new file mode 100644
index 000000000..250fcbb3c
--- /dev/null
+++ b/docs/recipes/extension-websocket.md
@@ -0,0 +1,250 @@
+
+# WebSocket Extension
+
+This extension adds a WebSocket Server to your Lucee Server that runs over `TCP` on port 80 for `WS:` and 443 for `WSS:`
+
+WebSocket Listeners are created with a CFML Component - one per channel.
+
+## Installation
+
+The Extension can be installed via Lucee Administor
+
+![Lucee Admin: Extensions - Application](../_images/extension/websocket/lucee-admin-extension.png)
+
+Or downloaded the LEX file from [https://download.lucee.org/](https://download.lucee.org/) and save to `
+
+![Lucee Download LEX File](../_images/extension/websocket/websocket-lex.png)
+
+eg Dockerfile
+
+```Dockerfile
+ADD https://ext.lucee.org/org.lucee.websocket.extension-1.0.0.4-BETA.lex /lucee/lucee-server/deploy/
+```
+
+Or using Environment Variables
+
+eg docker-compose.yml
+
+```yml
+environment:
+ - LUCEE_EXTENSIONS=07082C66-510A-4F0B-B5E63814E2FDF7BE;version=1.0.0.4-BETA
+```
+
+## Configuration
+
+By default, Lucee Server will look in `{lucee-config}/websockets/` for WebSocket Components.
+
+Lucee Server will create a config file if one does not exists at `{lucee-config}websocket.json` with the following defaults
+
+*{lucee-config}: /lucee/lucee-server/context*
+
+```json
+{
+ "directory":"{lucee-config}/websockets/",
+ "requestTimeout":50,
+ "idleTimeout":300
+}
+```
+
+The WebSocket Extension comes with a helper function `websocketInfo()` that well show the current configurations settings. More on other details later ...
+
+![websocketInfo()](../_images/extension/websocket/websocketInfo.png)
+TODO: update with new version
+
+## Component
+
+```lucee
+component hint="used to test websocket client" {
+
+ public static function onFirstOpen(wsclients) {}
+
+ function onOpen(wsclient) {}
+
+ function onOpenAsync(wsclient) {}
+
+ function onMessage(wsclient, message) {}
+
+ function onClose(wsclient, ReasonPhrase) {}
+
+ function onError(wsclient,cfcatch) {}
+
+ public static function onLastClose() {}
+
+}
+```
+
+### Javascript Client
+
+Given that the Component was saved as `{lucee-config}/websockets/test.cfc`, here is native Javascript to open and use a connection to your Lucee WebSocket:
+
+```javascript
+socket = new WebSocket("ws://127.0.0.1:80/ws/test");
+
+socket.onopen = function(evt) {
+ console.log(['onopen()', evt]);
+};
+
+socket.onmessage = (event) => {
+ console.log(event.data);
+};
+
+socket.onerror = function(error) {
+ console.error(error);
+};
+
+socket.send("Hello, Lucee Extension!");
+
+socketclose();
+```
+
+### Broadcast Message to all Clients
+A broadcast is a message send to all connected clients
+
+To be able to do this, we need to know who is connected. The first time a connection is made, `onFirstOpen(wsclients)` is fired. `wsclients` is a Java class with the following methods
+
+```java
+size():number // the number of clients connected
+broadcast(any message):boolean // send message to all clients
+getClients():Client[] // return array of all clients currently connected
+close():void // closes all clients
+```
+
+SO we can save that for furture use
+
+```lucee
+public static function onFirstOpen(wsclients) {
+ static.wsclients = arguments.wsclients;
+}
+```
+
+For example
+```lucee
+function onOpen(wsclient) {
+ static.wsclients.broadcast("There are now ##static.wsclients.size()## connections");
+}
+```
+
+### Send Message to one Client
+
+When a connection is instantiated, `onOpen(wsclient)` is fired. `wsclient` is a Java class with the following methods
+
+```java
+client.broadcast(message):void // send message to all connected clients
+client.send(message):void // send message to the client
+client.isOpen():boolean // is the client still connected?
+client.isClose():boolean // is the client no longer connected?
+client.close():void // closes the connection of the client
+```
+
+To send a message using wsclient
+
+```lucee
+function onOpen(wsclient) {
+ arguments.wsclient.send("You are connected to Lucee WebSocket");
+}
+```
+
+You can also send a message from `onOpen()` by returning a string
+
+```lucee
+function onOpen(wsclient) {
+ return "Welcome to the test websocket channel";
+}
+```
+
+You can add your own function to the WebSocket Componet
+
+```lucee
+public void function sendMessage(
+ required string jsonData
+) {
+ variables.wsclient.send(jsonData);
+}
+
+function onOpen(wsclient) {
+ sendMessage("Hello, Lucee WebSocket!");
+}
+```
+
+## Using Lucee WebSocket to PUSH data to Client
+With webSocets being a bidirectional communication channel, your Lucee Server no longer limited to responding to a *request*, it can now *push* data to the client.
+
+This means the user no longer has to refresh a page to see if data is updated, or have a Javascript looping function that is continuosly calling a ReST API to get lasted data.
+
+When your application has data ready for the user, have the WebSocket push the data to the cient!
+
+### Make use of Static Function
+
+Add a thread to start a background process, and have it continuously looping for as long as there are clients connected
+
+```lucee
+public static function onFirstOpen(wsclients) {
+ static.wsclients = arguments.wsclients;
+ thread name="threadDataQueue" oClients=static.wsclients {
+ while( attributes.oClients.size() > 0 ) {
+ data = getDataFromSomewhere();
+ attributes.oClients.broadcastMessage(data);
+ sleep(1000);
+ }
+ }
+}
+```
+
+Function `getDataFromSomewhere()` is respoible for obtaining the data that needs to be sent to the client. RedisQueue is an example of where data can be stored. Your Lucee application can Push data to a Redis Queue, and `getDataFromSomewhere()` can Pop one record at a time.
+
+### Using websocketInfo() to Send Message to Client
+
+`websocketInfo()` also has an array of instances - one for each client call to a WebSocket Component. So looping through the array, gives you access to the Component, and then you can call any of it'sfunction
+
+For Example ( *excuding role management functions* )
+
+```lucee
+component hint="Test WebSocket" {
+ variables.roles = [];
+
+ public boolean function hasRole(
+ required string role
+ ) {
+ return ( variables.roles.find(arguments.role) > 0 );
+ }
+
+ public void function sendMessage(
+ required string jsonData
+ ) {
+ variables.wsclient.send(jsonData);
+ }
+ ...
+}
+```
+
+```lucee
+var wsInfo = websocketInfo(false);
+if ( !wsInfo.instances.len() )
+ return;
+
+var wsInstances = wsInfo.instances;
+
+var item = getRedisData();
+var stItem = deserializeJSON(item);
+for ( var wsI in wsInstances) {
+ if ( GetMetadata(wsI).name == 'test' && wsI.hasRole(stItem.data.role) ) {
+ wsI.sendMessage(item);
+ }
+}
+```
+[Task Event Gateway](event-gateways-overview.md) is a good candidate for this script
+
+*TODO: link to recipe page*
\ No newline at end of file