diff --git a/data_src/index.html b/data_src/index.html
index edeed5b7104e84e7135f1e8a1318bbbf5604384f..d44984476ab0624284db1748bfcd6878c8f9ab73 100644
--- a/data_src/index.html
+++ b/data_src/index.html
@@ -26,12 +26,12 @@
 
           <div class="row mb-3 px-3">
             <label for="rangeBrightness" class="col-form-label">Brightness</label>
-            <input type="range" class="form-range rangeConfig" id="rangeBrightness" data-name="brightness" min="1"
+            <input type="range" class="form-range rangeSetting" id="rangeBrightness" data-name="brightness" min="1"
               max="100" steps="1" disabled>
           </div>
           <div class="row mb-3 px-3">
             <label for="rangeSpeed" class="col-form-label">Speed</label>
-            <input type="range" class="form-range rangeConfig" id="rangeSpeed" data-name="interval" min="1" max="100"
+            <input type="range" class="form-range rangeSetting" id="rangeSpeed" data-name="interval" min="1" max="100"
               steps="10" disabled>
           </div>
           <div class="row mb-3 px-3 mt-5">
@@ -44,10 +44,8 @@
         <div class="card-footer text-body-secondary py-3">
           <div class="row">
             <div class="col-6">
-              <button type="button" class="btn btn-sm btn-success btnAction" data-action="load" disabled>Load</button>
-            </div>
-            <div class="col-6">
-              <button type="button" class="btn btn-sm btn-success btnAction" data-action="save" disabled>Save</button>
+              <button type="button" class="btn btn-sm btn-success btnAction me-1" data-action="loadSettings" disabled>Load</button>
+              <button type="button" class="btn btn-sm btn-success btnAction" data-action="saveSettings" disabled>Save</button>
             </div>
             <div class="col-6 text-end">
               <button type="button" class="btn btn-sm btn-outline-secondary me-1" data-bs-toggle="collapse"
@@ -70,7 +68,7 @@
         </h5>
         <div class="card-body">
 
-          <textarea id="wsMessages" class="form-control mb-2 font-monospace" rows="10"></textarea>
+          <textarea id="wsMessages" class="form-control mb-2 font-monospace" rows="10" spellcheck="false"></textarea>
           <div id="input_div">
             <div class="input-group">
               <span class="input-group-text">➡️</span>
diff --git a/data_src/main.js b/data_src/main.js
index 28d07bfa600650c2e2f9a38388afda4ab833cc04..fe3f97b492c1afa1af45181da71b74b264686ecd 100644
--- a/data_src/main.js
+++ b/data_src/main.js
@@ -1,6 +1,6 @@
 var wsUrl = 'ws://' + document.location.host + '/ws';
 
-var config = {
+var settings = {
     brightness: 0,
     interval: 0,
 };
@@ -11,7 +11,7 @@ $(document).ready(function () {
     startSocket();
 });
 
-$(document).on('input change', '.rangeConfig', function () {
+$(document).on('change', '.rangeSetting', function () {
     var setting = $(this).data('name');
     var value = $(this).val();
     switch (setting) {
@@ -22,38 +22,35 @@ $(document).on('input change', '.rangeConfig', function () {
             value = mapRange(value, 1, 100, 1000, 10);
             break;
     }
-    config[setting] = value;
+    settings[setting] = value;
     var payload = {
-        'config': config
+        'settings': settings
     };
     wsSend(payload);
 });
 
 $('.btnAction').on('click', function () {
     var action = $(this).data('action');
-    var payload = {
-        'action': action
-    };
-    wsSend(payload);
+    sendAction(action);
 });
 
-$("#prompt").onkeydown = function (e) {
-    if (e.keyCode == 13 && $("#prompt").value != "") {
+$("#prompt").on('keydown', function (e) {
+    if (e.keyCode == 13 && $("#prompt").val() != "") {
         var val = $("#prompt").val();
-        wsSend(val);
+        wsSend(JSON.parse(val));
         $("#prompt").val("");
     }
-}
+});
 
 function uiEnabled(enabled) {
     if (enabled) {
         $('#spinner').addClass('invisible');
         $('.btnAction').prop('disabled', false);
-        $('.rangeConfig').prop('disabled', false);
+        $('.rangeSetting').prop('disabled', false);
     } else {
         $('#spinner').removeClass('invisible');
         $('.btnAction').prop('disabled', true);
-        $('.rangeConfig').prop('disabled', true);
+        $('.rangeSetting').prop('disabled', true);
     }
 }
 
@@ -63,14 +60,11 @@ function addMessage(msg) {
     txt.scrollTop(txt[0].scrollHeight - txt.height());
 }
 
-function wsSend(msg) {
-    uiEnabled(false);
-    var json = JSON.stringify(msg);
-    ws.send(msg).done(function () {
-        addMessage("➡️ " + json);
-        uiEnabled(true);
+function wsSend(obj) {
+    ws.send(obj).done(function () {
+        addMessage("➡️ " + JSON.stringify(obj));
     }).fail(function (e) {
-        addMessage("❗️ " + json);
+        addMessage("❗️ " + JSON.stringify(obj));
     });
 }
 
@@ -78,11 +72,13 @@ var ws;
 function startSocket() {
     ws = $.simpleWebSocket({
         url: wsUrl,
+        timeout: 5000,
         onOpen: function (e) {
-            console.log("WS: connected");
-            addMessage("✅ connected");
-            getConfig();
-            uiEnabled(true);
+            ws.isConnected(function (connected) {
+                console.log("WS: connected");
+                addMessage("✅ connected");
+                sendAction('getSettings');
+            });
         },
         onClose: function (e) {
             uiEnabled(false);
@@ -97,28 +93,27 @@ function startSocket() {
     });
 
     ws.listen(function (data) {
-        console.log(data);
-        var json = JSON.stringify(data);
-        var msg = "⬅️ " + json;
-        addMessage(msg);
-        if (data.config) {
-            loadConfig(data.config);
+        addMessage("⬅️ " + JSON.stringify(data));
+        if (data.settings) {
+            loadSettings(data.settings);
         }
     });
 }
 
-function getConfig() {
+function sendAction(action) {
     var payload = {
-        'action': 'load'
+        'action': action
     };
     wsSend(payload);
 }
 
-function loadConfig(data) {
-    config.brightness = data.brightness;
-    config.interval = data.interval;
+function loadSettings(data) {
+    settings.brightness = data.brightness;
+    settings.interval = data.interval;
+    uiEnabled(true);
     $('#rangeBrightness').val(mapRange(data.brightness, 8, 255, 1, 100));
     $('#rangeSpeed').val(mapRange(data.interval, 1000, 10, 1, 100));
+    sendAction('getHighscores');
 }
 
 function mapRange(number, inMin, inMax, outMin, outMax) {
diff --git a/src/gameoflife.cpp b/src/gameoflife.cpp
index 58995c62fda1936892a00e3a73699df5d9db0901..f26874938b581f9b6f4e341c644408750ff94961 100644
--- a/src/gameoflife.cpp
+++ b/src/gameoflife.cpp
@@ -3,6 +3,7 @@
 #include "gameoflife.h"
 #include "network.h"
 #include "utils.h"
+#include "settings.h"
 
 // https://github.com/Stavrosfil/game-of-life-esp32
 
@@ -162,6 +163,10 @@ void gameLoop()
       finalTicks = currentTick - noEvolutionTicksLimit;
       currentMillis = millis();
       showEndScreen(finalTicks);
+      sendGameStats(gameEra, finalTicks, cellsAliveNow);
+      if(updateHighscores(gameEra, finalTicks, cellsAliveNow)) {
+        sendHighscores();
+      }
       gameOver = true;
     }
   }
diff --git a/src/network.cpp b/src/network.cpp
index 77abde2befa27739b4813a81554d12894502a222..cdbc9b0f6b637397c8a74d8af0cb1cd54548b1f5 100644
--- a/src/network.cpp
+++ b/src/network.cpp
@@ -181,15 +181,6 @@ void onTelnetInput(String str)
   }
 }
 
-DynamicJsonDocument getConfigJson()
-{
-  DynamicJsonDocument doc(200);
-  JsonObject config = doc.createNestedObject("config");
-  config["brightness"] = defaultBrightness;
-  config["interval"] = gameInterval;
-  return doc;
-}
-
 void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
 {
   if (type == WS_EVT_CONNECT)
@@ -236,19 +227,23 @@ void handleJson(uint8_t *data)
     return;
   }
 
-  if (doc.containsKey("config"))
+  if (doc.containsKey("settings"))
   {
-    updateConfig(doc);
+    updateSettings(doc);
   }
 
   if (doc.containsKey("action"))
   {
-    if (doc["action"] == "load")
+    if (doc["action"] == "getSettings")
+    {
+      sendSettings();
+    }
+    else if (doc["action"] == "loadSettings")
     {
       loadSettings();
-      sendConfig();
+      sendSettings();
     }
-    else if (doc["action"] == "save")
+    else if (doc["action"] == "saveSettings")
     {
       saveSettings();
     }
@@ -256,6 +251,10 @@ void handleJson(uint8_t *data)
     {
       addGlider();
     }
+    else if (doc["action"] == "getHighscores")
+    {
+      sendHighscores();
+    }
     else if (doc["action"] == "reboot")
     {
       ESP.restart();
@@ -263,16 +262,46 @@ void handleJson(uint8_t *data)
   }
 }
 
-void updateConfig(StaticJsonDocument<200U> doc)
+void updateSettings(StaticJsonDocument<200U> doc)
 {
-  gameInterval = doc["config"]["interval"];
-  defaultBrightness = doc["config"]["brightness"];
+  gameInterval = doc["settings"]["interval"];
+  defaultBrightness = doc["settings"]["brightness"];
   displayBrightness(defaultBrightness);
 }
 
-void sendConfig()
+void sendSettings()
 {
-  DynamicJsonDocument doc = getConfigJson();
+  DynamicJsonDocument doc(200);
+  JsonObject settings = doc.createNestedObject("settings");
+  settings["brightness"] = defaultBrightness;
+  settings["interval"] = gameInterval;
+  size_t strsize = measureJson(doc) + 1;
+  char json[strsize];
+  serializeJson(doc, json, strsize);
+  ws.textAll(json);
+}
+
+void sendHighscores()
+{
+  DynamicJsonDocument doc(200);
+  JsonObject highscores = doc.createNestedObject("highscores");
+  Highscores hs = getHighscores();
+  highscores["games"] = hs.games;
+  highscores["ticks"] = hs.ticks;
+  highscores["cells"] = hs.cells;
+  size_t strsize = measureJson(doc) + 1;
+  char json[strsize];
+  serializeJson(doc, json, strsize);
+  ws.textAll(json);
+}
+
+void sendGameStats(int game, int ticks, int cells)
+{
+  DynamicJsonDocument doc(200);
+  JsonObject stats = doc.createNestedObject("stats");
+  stats["game"] = game;
+  stats["ticks"] = ticks;
+  stats["cells"] = cells;
   size_t strsize = measureJson(doc) + 1;
   char json[strsize];
   serializeJson(doc, json, strsize);
diff --git a/src/network.h b/src/network.h
index d9d85db938bda748f73e6f93f1bb1e3ae66b99ec..b57b5b7afd867e1bd0a8faf5020a4a9ca9b88c03 100644
--- a/src/network.h
+++ b/src/network.h
@@ -31,7 +31,9 @@ void onTelnetConnectionAttempt(String ip);
 void onTelnetInput(String str);
 void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len);
 void handleJson(uint8_t* data);
-void updateConfig(StaticJsonDocument<200U> doc);
-void sendConfig();
+void updateSettings(StaticJsonDocument<200U> doc);
+void sendSettings();
+void sendHighscores();
+void sendGameStats(int game, int ticks, int cells);
 
 #endif
diff --git a/src/settings.cpp b/src/settings.cpp
index c9fc9d3bac629985cab9cca603f2170b908b195f..a7c7875d9001e8c6189d0cfa522cd7a9f1ee85aa 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -18,3 +18,33 @@ void saveSettings() {
   preferences.putUInt("interval", gameInterval);
   preferences.end();  
 }
+
+bool updateHighscores(int games, int ticks, int cells) {
+  bool changed = false;
+  Highscores hs = getHighscores();
+  preferences.begin("highscores", false);
+  if (games > hs.games) {
+    preferences.putUInt("games", games);
+    changed = true;
+  }
+  if (ticks > hs.ticks) {
+    preferences.putUInt("ticks", ticks);
+    changed = true;
+  }
+  if (cells > hs.cells) {
+    preferences.putUInt("cells", cells);
+    changed = true;
+  }
+  preferences.end();  
+  return changed;
+}
+
+Highscores getHighscores() {
+  Highscores hs;
+  preferences.begin("highscores", true);
+  hs.games = preferences.getUInt("games", 0);
+  hs.ticks = preferences.getUInt("ticks", 0);
+  hs.cells = preferences.getUInt("cells", 0);
+  preferences.end();  
+  return hs;
+}
diff --git a/src/settings.h b/src/settings.h
index 189c02ed788189b6d348f947722bf6b4698d6160..05a0964a8b8edbcfb8c7ea033b0a0f6f888d0926 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -8,7 +8,15 @@
 extern int defaultBrightness;
 extern int gameInterval;
 
+typedef struct {
+    int games;
+    int ticks;
+    int cells;
+} Highscores;
+
 void loadSettings();
 void saveSettings();
+bool updateHighscores(int games, int ticks, int cells);
+Highscores getHighscores();
 
 #endif