diff --git a/templates/index.html b/templates/index.html
index e2fd5767bfa218a1f4203d87f736fba7d2a2c123..38b595670c16d0dc0b11d69bcede4568c5a9fe65 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -23,6 +23,7 @@
         <p style="font-size: 23px">Linearity: <span id="linearity" style="color: red"></span></p>
         <p style="font-size: 23px">Max spot size: <span id="max_spot_size" style="color: red"></span></p>
         <p style="font-size: 23px">Ion roundness: <span id="roundness" style="color: red"></span>%</p>
+        <p style="font-size: 23px">Fit error: <span id="fit_error" style="color: red"></span> (Moving avg: <span id="fit_avg" style="color: red"></span>) <span id="response" style="color: red"></span></p>
         <h2 style="font-size: 35px">Stream:</h2>
         <span class="img-container">
             <img src="{{ url_for('video_feed') }}" width="450" height="350" alt="Streaming">
@@ -36,6 +37,12 @@
                 for (let key in jsonResponse) {
                     document.getElementById(key).innerText = jsonResponse[key];
                 }
+                if (Number(document.getElementById("fit_avg").innerText) >= 20) {
+                document.getElementById("response").innerText = "Calibration needed!"
+                }
+                else{
+                    document.getElementById("response").innerText = ""
+            }
             };
 
             setInterval(() => {
diff --git a/tools.py b/tools.py
index 9d620a3c7c77dd26192e2b1fd2196f9d013d3623..4f1b284415455447681e031a08a1a723006bde6b 100644
--- a/tools.py
+++ b/tools.py
@@ -48,6 +48,7 @@ class Main:
         # Instantiate classes
         self.memory = Memory()
         self.count_avg = MovingAverage()
+        self.fit_avg = FitAverage()
         self.trap_state = TrapState()
 
         # Define class attributes
@@ -87,7 +88,9 @@ class Main:
                         'reorder_avg': self.count_avg.moving_avg,
                         'reorder_flag': -1,
                         'max_spot_size': -1,
-                        'roundness': -1
+                        'roundness': -1,
+                        'fit_error': -1,
+                        'fit_avg': -1
                         }
 
             elif not ion_cloud:
@@ -121,7 +124,8 @@ class Main:
             linearity = ion_linearity(coord)
 
             if len(coord) > 1 and dist_factor is not None:
-                coord = dark_ions(img, coord, dist_factor)
+                coord, fit_error = dark_ions(img, coord, dist_factor)
+                self.fit_avg.update_value(fit_error)
         else:
             roundness = 0
             max_int, num_pix = (0, 0)
@@ -163,7 +167,9 @@ class Main:
             'reorder_avg': self.count_avg.moving_avg,
             'reorder_flag': reorder_flag,
             'max_spot_size': int(max_spot_size),
-            'roundness': int(roundness)  
+            'roundness': int(roundness),
+            'fit_error': int(fit_error),
+            'fit_avg': int(self.fit_avg.moving_avg)
             }
 
     def _save_in_memory(self, output):
@@ -278,6 +284,38 @@ class Memory:
         return max_value
 
 
+class FitAverage:
+    """
+    Compute moving average of fit error
+    """
+    def __init__(self):
+        self.value = 0
+        self.value_history = [0]
+        self.moving_avg = 0
+
+        self.update_history()
+
+    def update_history(self):
+        """
+        Every second update history and compute moving average.
+        """
+        _thread = threading.Timer(1, self.update_history)
+        _thread.daemon = True
+        _thread.start()
+        self.value_history.append(self.value)
+        if len(self.value_history) > 60:
+            self.value_history.pop(0)
+        self.moving_avg = np.mean(self.value_history)
+        min_val = min(self.value_history)
+        self.value_history = [i - min_val for i in self.value_history]
+        self.value -= min_val
+
+    def update_value(self, value):
+        """
+        Update value.
+        """
+        self.value = value
+
 class MovingAverage:
     """
     Keep record of number of reorders of the ions and return a moving average of
@@ -603,7 +641,7 @@ def dark_ions(image, coord, dist_factor):
         #     warnings.warn("Loss is too high... "
         #     "Try calculating a new factor value using calibrate() function.")
 
-    return coord
+    return coord, loss.min()
 
 
 def acquire_semaphore_read(name: str, timeout=1):