diff --git a/img/qr.jpg b/img/qr.jpg
new file mode 100644
index 0000000..a8f6e34
Binary files /dev/null and b/img/qr.jpg differ
diff --git a/index.php b/index.php
index 9fa90c4..27dc946 100644
--- a/index.php
+++ b/index.php
@@ -27,6 +27,7 @@ $display_servers_guru = isset($config['servers_guru']) && $config['servers_guru'
 $attribution = isset($config['attribution']) ? $config['attribution'] : '';
 $preferred_currencies = isset($config['preferred_currencies']) ? $config['preferred_currencies'] : [];
 $github_url = isset($config['github_url']) ? $config['github_url'] : 'https://github.com/rottenwheel/moner.ooo/';
+$footer_html = isset($config['footer_html']) ? $config['footer_html'] : '';
 
 // Extract the keys
 $currencies = array_map('strtoupper', array_keys($api_cg));
diff --git a/package-lock.json b/package-lock.json
index e4bb07c..70ae82f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -124,30 +124,10 @@
 				"url": "https://opencollective.com/popperjs"
 			}
 		},
-		"node_modules/@types/eslint": {
-			"version": "8.56.10",
-			"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
-			"integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==",
-			"license": "MIT",
-			"dependencies": {
-				"@types/estree": "*",
-				"@types/json-schema": "*"
-			}
-		},
-		"node_modules/@types/eslint-scope": {
-			"version": "3.7.7",
-			"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
-			"integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
-			"license": "MIT",
-			"dependencies": {
-				"@types/eslint": "*",
-				"@types/estree": "*"
-			}
-		},
 		"node_modules/@types/estree": {
-			"version": "1.0.5",
-			"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
-			"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+			"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
 			"license": "MIT"
 		},
 		"node_modules/@types/json-schema": {
@@ -379,10 +359,10 @@
 				"node": ">=0.4.0"
 			}
 		},
-		"node_modules/acorn-import-assertions": {
-			"version": "1.9.0",
-			"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
-			"integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
+		"node_modules/acorn-import-attributes": {
+			"version": "1.9.5",
+			"resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
+			"integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
 			"license": "MIT",
 			"peerDependencies": {
 				"acorn": "^8"
@@ -833,9 +813,9 @@
 			"license": "MIT"
 		},
 		"node_modules/enhanced-resolve": {
-			"version": "5.16.1",
-			"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz",
-			"integrity": "sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==",
+			"version": "5.17.1",
+			"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
+			"integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
 			"license": "MIT",
 			"dependencies": {
 				"graceful-fs": "^4.2.4",
@@ -1587,9 +1567,9 @@
 			}
 		},
 		"node_modules/picocolors": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
-			"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
+			"integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
 			"license": "ISC"
 		},
 		"node_modules/pkg-dir": {
@@ -1605,9 +1585,9 @@
 			}
 		},
 		"node_modules/postcss": {
-			"version": "8.4.38",
-			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
-			"integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+			"version": "8.4.47",
+			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
+			"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
 			"dev": true,
 			"funding": [
 				{
@@ -1626,8 +1606,8 @@
 			"license": "MIT",
 			"dependencies": {
 				"nanoid": "^3.3.7",
-				"picocolors": "^1.0.0",
-				"source-map-js": "^1.2.0"
+				"picocolors": "^1.1.0",
+				"source-map-js": "^1.2.1"
 			},
 			"engines": {
 				"node": "^10 || ^12 || >=14"
@@ -1965,9 +1945,9 @@
 			}
 		},
 		"node_modules/source-map-js": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
-			"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+			"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
 			"dev": true,
 			"license": "BSD-3-Clause",
 			"engines": {
@@ -2248,21 +2228,20 @@
 			}
 		},
 		"node_modules/webpack": {
-			"version": "5.91.0",
-			"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz",
-			"integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==",
+			"version": "5.95.0",
+			"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz",
+			"integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==",
 			"license": "MIT",
 			"dependencies": {
-				"@types/eslint-scope": "^3.7.3",
 				"@types/estree": "^1.0.5",
 				"@webassemblyjs/ast": "^1.12.1",
 				"@webassemblyjs/wasm-edit": "^1.12.1",
 				"@webassemblyjs/wasm-parser": "^1.12.1",
 				"acorn": "^8.7.1",
-				"acorn-import-assertions": "^1.9.0",
+				"acorn-import-attributes": "^1.9.5",
 				"browserslist": "^4.21.10",
 				"chrome-trace-event": "^1.0.2",
-				"enhanced-resolve": "^5.16.0",
+				"enhanced-resolve": "^5.17.1",
 				"es-module-lexer": "^1.2.1",
 				"eslint-scope": "5.1.1",
 				"events": "^3.2.0",
diff --git a/src/js/main.js b/src/js/main.js
index 7390237..9f99bd2 100644
--- a/src/js/main.js
+++ b/src/js/main.js
@@ -1,163 +1,182 @@
 import 'bootstrap/dist/css/bootstrap.min.css';
-import 'bootstrap/dist/js/bootstrap.bundle.min';
-
 import '../css/custom.css';
 
-import Tooltip from "bootstrap/js/dist/tooltip";
-var tooltipTriggerList = [].slice.call(
-  document.querySelectorAll('[data-toggle="tooltip"]')
-);
-var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
-  return new Tooltip(tooltipTriggerEl, { placement: "top" });
-});
+import Tooltip from 'bootstrap/js/dist/tooltip';
+
+const tooltipTriggerList = Array.from(document.querySelectorAll('[data-toggle="tooltip"]'));
+const tooltipList = tooltipTriggerList.map(tooltipTriggerEl => new Tooltip(tooltipTriggerEl, { placement: 'top' }));
 console.log(tooltipList);
 
 let lastModifiedField = 'xmr';
+const exchangeRates = {};
 
-var exchangeRates = {};
+const runConvert = () =>
+    lastModifiedField === 'xmr' ? xmrConvert() : fiatConvert();
 
-document.addEventListener('DOMContentLoaded', function () {
-  const copyXMRBtn = document.getElementById('copyXMRBtn');
-  const copyFiatBtn = document.getElementById('copyFiatBtn');
-  const xmrInput = document.getElementById('xmrInput');
-  const fiatInput = document.getElementById('fiatInput');
-  const selectBox = document.getElementById('selectBox');
-  const convertXMRToFiatBtn = document.getElementById('convertXMRToFiat');
-  const convertFiatToXMRBtn = document.getElementById('convertFiatToXMR');
-  const fiatButtons = document.querySelectorAll('.fiat-btn');
+let updateInterval
+const startFetching = () => updateInterval = setInterval(fetchUpdatedExchangeRates, 5000);
+const stopFetching = () => {
+    clearInterval(updateInterval)
+    updateInterval = null;
+};
 
-  // Add event listeners for the currency buttons
-  fiatButtons.forEach(button => {
-    button.addEventListener('click', (e) => {
-      e.preventDefault();
-      selectBox.value = button.textContent;
-      if (lastModifiedField === 'xmr') {
-        xmrConvert();
-      } else {
-        fiatConvert();
-      }
-      history.pushState(null, '', `?in=${button.textContent}`);
-    });
-  });
+const inactivityTimeout = 30 * 1000; // 30 seconds
+let lastActivity = Date.now()
 
-  // Add event listeners for the copy buttons
-  copyXMRBtn.addEventListener('click', copyToClipBoardXMR);
-  copyFiatBtn.addEventListener('click', copyToClipBoardFiat);
-
-  // Add event listeners for the XMR input field
-  xmrInput.addEventListener('change', () => xmrConvert(xmrInput.value));
-  xmrInput.addEventListener('keyup', () => {
-    xmrInput.value = xmrInput.value.replace(/[^\.^,\d]/g, '');
-    xmrInput.value = xmrInput.value.replace(/\,/, '.');
-    if (xmrInput.value.split('.').length > 2) {
-      xmrInput.value = xmrInput.value.slice(0, -1);
-    }
-    xmrConvert(xmrInput.value);
-  });
-  xmrInput.addEventListener('input', () => {
-    lastModifiedField = 'xmr';
-  });
-
-  // Add event listeners for the fiat input field
-  fiatInput.addEventListener('change', () => fiatConvert(fiatInput.value));
-  fiatInput.addEventListener('keyup', () => {
-    fiatInput.value = fiatInput.value.replace(/[^\.^,\d]/g, '');
-    fiatInput.value = fiatInput.value.replace(/\,/, '.');
-    if (fiatInput.value.split('.').length > 2) {
-      fiatInput.value = fiatInput.value.slice(0, -1);
-    }
-    fiatConvert(fiatInput.value);
-  });
-  fiatInput.addEventListener('input', () => {
-    lastModifiedField = 'fiat';
-  });
-
-  // Add event listener for the select box to change the conversion
-  selectBox.addEventListener('change', () => {
-    if (lastModifiedField === 'xmr') {
-      xmrConvert(selectBox.value)
+const resetActivity = () => lastActivity = Date.now()
+const checkInactivity = () => {
+    if (Date.now() - lastActivity > inactivityTimeout) {
+        console.log('Inactivity detected, stopping exchange rate updates');
+        stopFetching();
     } else {
-      fiatConvert(selectBox.value)
+        requestAnimationFrame(checkInactivity);
     }
-  });
+}
 
-  // Hide the conversion buttons if JavaScript is enabled
-  convertXMRToFiatBtn.style.display = 'none';
-  convertFiatToXMRBtn.style.display = 'none';
+document.addEventListener('focus', () => {
+    const focused = document.hasFocus();
+    console.log(`Page is ${focused ? 'visible' : 'hidden'}`); 
 
-  // Fetch updated exchange rates immediately, then every 5 seconds
-  fetchUpdatedExchangeRates();
-  setInterval(fetchUpdatedExchangeRates, 5000);
+    if (focused && !updateInterval) {
+        console.log('Restarting exchange rate updates');
+        startFetching();
+
+        resetActivity();
+        requestAnimationFrame(checkInactivity);
+    } else {
+        stopFetching();
+    }
+});
+window.addEventListener('mousemove', resetActivity);
+window.addEventListener('keydown', resetActivity);
+window.addEventListener('touchstart', resetActivity);
+
+requestAnimationFrame(checkInactivity);
+
+document.addEventListener('DOMContentLoaded', () => {
+    const copyXMRBtn = document.getElementById('copyXMRBtn');
+    const copyFiatBtn = document.getElementById('copyFiatBtn');
+    const xmrInput = document.getElementById('xmrInput');
+    const fiatInput = document.getElementById('fiatInput');
+    const selectBox = document.getElementById('selectBox');
+    const convertXMRToFiatBtn = document.getElementById('convertXMRToFiat');
+    const convertFiatToXMRBtn = document.getElementById('convertFiatToXMR');
+    const fiatButtons = document.querySelectorAll('.fiat-btn');
+    
+    // Add event listeners for the currency buttons
+    fiatButtons.forEach(button => {
+        button.addEventListener('click', (e) => {
+            e.preventDefault();
+            selectBox.value = button.textContent;
+            runConvert();
+            history.pushState(null, '', `?in=${button.textContent}`);
+        });
+    });
+    
+    // Add event listeners for the copy buttons
+    copyXMRBtn.addEventListener('click', copyToClipboardXMR);
+    copyFiatBtn.addEventListener('click', copyToClipboardFiat);
+    
+    // Add event listeners for the XMR input field
+    xmrInput.addEventListener('change', xmrConvert);
+    xmrInput.addEventListener('keyup', () => {
+        xmrInput.value = xmrInput.value.replace(/[^\.^,\d]/g, '').replace(/\,/, '.');
+        if (xmrInput.value.split('.').length > 2) {
+            xmrInput.value = xmrInput.value.slice(0, -1);
+        }
+        xmrConvert();
+    });
+    xmrInput.addEventListener('input', () => lastModifiedField = 'xmr');
+    
+    // Add event listeners for the fiat input field
+    fiatInput.addEventListener('change', fiatConvert);
+    fiatInput.addEventListener('keyup', () => {
+        fiatInput.value = fiatInput.value.replace(/[^\.^,\d]/g, '').replace(/\,/, '.');
+        if (fiatInput.value.split('.').length > 2) {
+            fiatInput.value = fiatInput.value.slice(0, -1);
+        }
+        fiatConvert();
+    });
+    fiatInput.addEventListener('input', () => lastModifiedField = 'fiat');
+    
+    // Add event listener for the select box to change the conversion
+    selectBox.addEventListener('change', runConvert);
+    
+    // Hide the conversion buttons if JavaScript is enabled
+    convertXMRToFiatBtn.style.display = 'none';
+    convertFiatToXMRBtn.style.display = 'none';
+    
+    // Fetch updated exchange rates immediately, then every 5 seconds
+    fetchUpdatedExchangeRates(true)
+    startFetching();
 });
 
-function fetchUpdatedExchangeRates() {
-  fetch('/coingecko.php')
+function fetchUpdatedExchangeRates(showAlert = false) {
+    fetch('/coingecko.php')
     .then(response => response.json())
     .then(data => {
-      // Update the exchangeRates object with the new values
-      for (const [currency, value] of Object.entries(data)) {
-        exchangeRates[currency.toUpperCase()] = value.lastValue;
-      }
-
-      updateTimeElement(data.time);
-
-      // Re-execute the appropriate conversion function
-      if (lastModifiedField === 'xmr') {
-        xmrConvert();
-      } else {
-        fiatConvert();
-      }
+        // Update the exchangeRates object with the new values
+        for (const [currency, value] of Object.entries(data)) {
+            exchangeRates[currency.toUpperCase()] = value.lastValue;
+        }
+        
+        updateTimeElement(data.time);
+        
+        // Re-execute the appropriate conversion function
+        runConvert();
     })
-    .catch(error => console.error('Error fetching exchange rates:', error));
+    .catch(e => {
+        const msg = `Error fetching exchange rates: ${e}`;
+        showAlert ? alert(msg) : console.error(msg);
+    });
 }
 
 function updateTimeElement(unixTimestamp) {
-  const date = new Date(unixTimestamp * 1000);
-  const hours = String(date.getHours()).padStart(2, '0');
-  const minutes = String(date.getMinutes()).padStart(2, '0');
-  const seconds = String(date.getSeconds()).padStart(2, '0');
-  const formattedTime = `${hours}:${minutes}:${seconds}`;
-
-  const u = document.querySelector('u');
-  u.textContent = formattedTime;
-  u.parentElement.innerHTML = u.parentElement.innerHTML.replace('Europe/Berlin', Intl.DateTimeFormat().resolvedOptions().timeZone);
+    const date = new Date(unixTimestamp * 1000);
+    const hours = String(date.getHours()).padStart(2, '0');
+    const minutes = String(date.getMinutes()).padStart(2, '0');
+    const seconds = String(date.getSeconds()).padStart(2, '0');
+    const formattedTime = `${hours}:${minutes}:${seconds}`;
+    
+    const u = document.querySelector('u');
+    u.textContent = formattedTime;
+    u.parentElement.innerHTML = u.parentElement.innerHTML.replace('Europe/Berlin', Intl.DateTimeFormat().resolvedOptions().timeZone);
 }
 
-function copyToClipBoardXMR() {
-  var content = document.getElementById('xmrInput');
-  content.select();
-  document.execCommand('copy');
+function copyToClipboardXMR() {
+    const content = document.getElementById('xmrInput');
+    content.select();
+    
+    // Using deprecated execCommand for compatibility with older browsers
+    document.execCommand('copy');
 }
 
-function copyToClipBoardFiat() {
-  var content = document.getElementById('fiatInput');
-  content.select();
-  document.execCommand('copy');
+function copyToClipboardFiat() {
+    const content = document.getElementById('fiatInput');
+    content.select();
+    
+    // Using deprecated execCommand for compatibility with older browsers
+    document.execCommand('copy');
 }
 
-function fiatConvert(value) {
-  let fiatAmount = document.getElementById("fiatInput").value;
-  let xmrValue = document.getElementById("xmrInput");
-  let selectBox = document.getElementById("selectBox").value;
-
-  if (exchangeRates[selectBox]) {
-    let value = fiatAmount / exchangeRates[selectBox];
-    xmrValue.value = value.toFixed(12);
-  }
+function fiatConvert() {
+    const fiatAmount = document.getElementById('fiatInput').value;
+    const xmrValue = document.getElementById('xmrInput');
+    const selectBox = document.getElementById('selectBox').value;
+    
+    if (exchangeRates[selectBox]) {
+        const value = fiatAmount / exchangeRates[selectBox];
+        xmrValue.value = value.toFixed(12);
+    }
 }
 
-function xmrConvert(value) {
-  let xmrAmount = document.getElementById("xmrInput").value;
-  let fiatValue = document.getElementById("fiatInput");
-  let selectBox = document.getElementById("selectBox").value;
-
-  if (exchangeRates[selectBox]) {
-    let value = xmrAmount * exchangeRates[selectBox];
-    fiatValue.value = value.toFixed(selectBox == 'BTC' || selectBox == 'LTC' || selectBox == 'ETH' || selectBox == 'XAG' || selectBox == 'XAU' ? 8 : 2);
-  }
-}
-
-window.copyToClipBoardXMR = copyToClipBoardXMR;
-window.copyToClipBoardFiat = copyToClipBoardFiat;
-window.fiatConvert = fiatConvert;
-window.xmrConvert = xmrConvert;
\ No newline at end of file
+function xmrConvert() {
+    const xmrAmount = document.getElementById('xmrInput').value;
+    const fiatValue = document.getElementById('fiatInput');
+    const selectBox = document.getElementById('selectBox').value;
+    
+    if (exchangeRates[selectBox]) {
+        const value = xmrAmount * exchangeRates[selectBox];
+        fiatValue.value = value.toFixed(['BTC', 'LTC', 'ETH', 'XAG', 'XAU'].includes(selectBox) ? 8 : 2);
+    }
+}
\ No newline at end of file
diff --git a/templates/index.php b/templates/index.php
index 997cc41..c7c8575 100644
--- a/templates/index.php
+++ b/templates/index.php
@@ -138,6 +138,7 @@
 
                 <small class="cursor-default text-white" lang="<?php echo $lang_meta; ?>">
                     <?php echo $footer_links . $getmonero . $countrymonero; ?>
+                    <?php echo $footer_html; ?>
                 </small>
             </div>
 
diff --git a/webpack.config.js b/webpack.config.js
index d1a8d91..ea9d9cd 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -29,7 +29,9 @@ module.exports = {
     }),
     new PurgeCSSPlugin({
       paths: glob.sync([
-        path.join(__dirname, 'index.php')
+        path.join(__dirname, 'index.php'),
+        path.join(__dirname, 'src/js/*.js'),
+        path.join(__dirname, 'templates/*.php'),
       ]),
       safelist: ['tooltip', 'fade', 'show', 'bs-tooltip-top', 'tooltip-inner', 'tooltip-arrow', 'btn-equals', 'btn-arrow', 'alert', 'alert-warning']
     })