diff --git a/db/knex_init_db.js b/db/knex_init_db.js
index 46bff4bfa..de9997dd4 100644
--- a/db/knex_init_db.js
+++ b/db/knex_init_db.js
@@ -202,7 +202,10 @@ async function createTables() {
         table.text("footer_text");
         table.text("custom_css");
         table.boolean("show_powered_by").notNullable().defaultTo(true);
-        table.string("google_analytics_tag_id");
+        table.string("analytics_id");
+        table.string("analytics_domain_url");
+        table.enu("analytics_type", [ "google", "umami", "plausible" ]).defaultTo(null);
+
     });
 
     // maintenance_status_page
diff --git a/db/knex_migrations/2025-02-17-2142-generalize-analytics.js b/db/knex_migrations/2025-02-17-2142-generalize-analytics.js
new file mode 100644
index 000000000..e4924feaf
--- /dev/null
+++ b/db/knex_migrations/2025-02-17-2142-generalize-analytics.js
@@ -0,0 +1,23 @@
+// Udpate status_page table to generalize analytics fields
+exports.up = function (knex) {
+    return knex.schema
+        .alterTable("status_page", function (table) {
+            table.renameColumn("google_analytics_tag_id", "analytics_id");
+            table.string("analytics_domain_url");
+            table.enu("analytics_type", [ "google", "umami", "plausible", "matomo" ]).defaultTo(null);
+
+        }).then(() => {
+            // After a succesful migration, add google as default for previous pages
+            knex("status_page").whereNotNull("analytics_id").update({
+                "analytics_type": "google",
+            });
+        });
+};
+
+exports.down = function (knex) {
+    return knex.schema.alterTable("status_page", function (table) {
+        table.renameColumn("analytics_id", "google_analytics_tag_id");
+        table.dropColumn("analytics_domain_url");
+        table.dropColumn("analytics_type");
+    });
+};
diff --git a/server/analytics/analytics.js b/server/analytics/analytics.js
new file mode 100644
index 000000000..79e570b9b
--- /dev/null
+++ b/server/analytics/analytics.js
@@ -0,0 +1,48 @@
+const googleAnalytics = require("./google-analytics");
+const umamiAnalytics = require("./umami-analytics");
+const plausibleAnalytics = require("./plausible-analytics");
+const matomoAnalytics = require("./matomo-analytics");
+
+/**
+ * Returns a string that represents the javascript that is required to insert the selected Analytics' script
+ * into a webpage.
+ * @param {typeof import("../model/status_page").StatusPage} statusPage Status page populate HTML with
+ * @returns {string} HTML script tags to inject into page
+ */
+function getAnalyticsScript(statusPage) {
+    switch (statusPage.analyticsType) {
+        case "google":
+            return googleAnalytics.getGoogleAnalyticsScript(statusPage.analyticsId);
+        case "umami":
+            return umamiAnalytics.getUmamiAnalyticsScript(statusPage.analyticsDomainUrl, statusPage.analyticsId);
+        case "plausible":
+            return plausibleAnalytics.getPlausibleAnalyticsScript(statusPage.analyticsDomainUrl, statusPage.analyticsId);
+        case "matomo":
+            return matomoAnalytics.getMatomoAnalyticsScript(statusPage.analyticsDomainUrl, statusPage.analyticsId);
+        default:
+            return null;
+    }
+}
+
+/**
+ * Function that checks wether the selected analytics has been configured properly
+ * @param {typeof import("../model/status_page").StatusPage} statusPage Status page populate HTML with
+ * @returns {boolean} Boolean defining if the analytics config is valid
+ */
+function isValidAnalyticsConfig(statusPage) {
+    switch (statusPage.analyticsType) {
+        case "google":
+            return statusPage.analyticsId != null;
+        case "umami":
+        case "plausible":
+        case "matomo":
+            return statusPage.analyticsId != null && statusPage.analyticsDomainUrl != null;
+        default:
+            return false;
+    }
+}
+
+module.exports = {
+    getAnalyticsScript,
+    isValidAnalyticsConfig
+};
diff --git a/server/google-analytics.js b/server/analytics/google-analytics.js
similarity index 100%
rename from server/google-analytics.js
rename to server/analytics/google-analytics.js
diff --git a/server/analytics/matomo-analytics.js b/server/analytics/matomo-analytics.js
new file mode 100644
index 000000000..fdc009e63
--- /dev/null
+++ b/server/analytics/matomo-analytics.js
@@ -0,0 +1,47 @@
+const jsesc = require("jsesc");
+const { escape } = require("html-escaper");
+
+/**
+ * Returns a string that represents the javascript that is required to insert the Matomo Analytics script
+ * into a webpage.
+ * @param {string} matomoUrl Domain name with tld to use with the Matomo Analytics script.
+ * @param {string} siteId Site ID to use with the Matomo Analytics script.
+ * @returns {string} HTML script tags to inject into page
+ */
+function getMatomoAnalyticsScript(matomoUrl, siteId) {
+    let escapedMatomoUrlJS = jsesc(matomoUrl, { isScriptContext: true });
+    let escapedSiteIdJS = jsesc(siteId, { isScriptContext: true });
+
+    if (escapedMatomoUrlJS) {
+        escapedMatomoUrlJS = escapedMatomoUrlJS.trim();
+    }
+
+    if (escapedSiteIdJS) {
+        escapedSiteIdJS = escapedSiteIdJS.trim();
+    }
+
+    // Escape the domain url for use in an HTML attribute.
+    let escapedMatomoUrlHTMLAttribute = escape(escapedMatomoUrlJS);
+
+    // Escape the website id for use in an HTML attribute.
+    let escapedSiteIdHTMLAttribute = escape(escapedSiteIdJS);
+
+    return `
+        <script type="text/javascript">
+            var _paq = window._paq = window._paq || [];
+            _paq.push(['trackPageView']);
+            _paq.push(['enableLinkTracking']);
+            (function() {
+                var u="//${escapedMatomoUrlHTMLAttribute}/";
+                _paq.push(['setTrackerUrl', u+'matomo.php']);
+                _paq.push(['setSiteId', ${escapedSiteIdHTMLAttribute}]);
+                var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
+                g.type='text/javascript'; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
+            })();
+        </script>
+    `;
+}
+
+module.exports = {
+    getMatomoAnalyticsScript,
+};
diff --git a/server/analytics/plausible-analytics.js b/server/analytics/plausible-analytics.js
new file mode 100644
index 000000000..14df98115
--- /dev/null
+++ b/server/analytics/plausible-analytics.js
@@ -0,0 +1,36 @@
+const jsesc = require("jsesc");
+const { escape } = require("html-escaper");
+
+/**
+ * Returns a string that represents the javascript that is required to insert the Plausible Analytics script
+ * into a webpage.
+ * @param {string} plausibleDomainUrl Domain name with tld to use with the Plausible Analytics script.
+ * @param {string} domainsToMonitor Domains to track seperated by a ',' to add Plausible Analytics script.
+ * @returns {string} HTML script tags to inject into page
+ */
+function getPlausibleAnalyticsScript(plausibleDomainUrl, domainsToMonitor) {
+    let escapedDomainUrlJS = jsesc(plausibleDomainUrl, { isScriptContext: true });
+    let escapedWebsiteIdJS = jsesc(domainsToMonitor, { isScriptContext: true });
+
+    if (escapedDomainUrlJS) {
+        escapedDomainUrlJS = escapedDomainUrlJS.trim();
+    }
+
+    if (escapedWebsiteIdJS) {
+        escapedWebsiteIdJS = escapedWebsiteIdJS.trim();
+    }
+
+    // Escape the domain url for use in an HTML attribute.
+    let escapedDomainUrlHTMLAttribute = escape(escapedDomainUrlJS);
+
+    // Escape the website id for use in an HTML attribute.
+    let escapedWebsiteIdHTMLAttribute = escape(escapedWebsiteIdJS);
+
+    return `
+        <script defer src="https://${escapedDomainUrlHTMLAttribute}/js/script.js" data-domain="${escapedWebsiteIdHTMLAttribute}"></script>
+    `;
+}
+
+module.exports = {
+    getPlausibleAnalyticsScript
+};
diff --git a/server/analytics/umami-analytics.js b/server/analytics/umami-analytics.js
new file mode 100644
index 000000000..5a4a172f9
--- /dev/null
+++ b/server/analytics/umami-analytics.js
@@ -0,0 +1,36 @@
+const jsesc = require("jsesc");
+const { escape } = require("html-escaper");
+
+/**
+ * Returns a string that represents the javascript that is required to insert the Umami Analytics script
+ * into a webpage.
+ * @param {string} domainUrl Domain name with tld to use with the Umami Analytics script.
+ * @param {string} websiteId Website ID to use with the Umami Analytics script.
+ * @returns {string} HTML script tags to inject into page
+ */
+function getUmamiAnalyticsScript(domainUrl, websiteId) {
+    let escapedDomainUrlJS = jsesc(domainUrl, { isScriptContext: true });
+    let escapedWebsiteIdJS = jsesc(websiteId, { isScriptContext: true });
+
+    if (escapedDomainUrlJS) {
+        escapedDomainUrlJS = escapedDomainUrlJS.trim();
+    }
+
+    if (escapedWebsiteIdJS) {
+        escapedWebsiteIdJS = escapedWebsiteIdJS.trim();
+    }
+
+    // Escape the domain url for use in an HTML attribute.
+    let escapedDomainUrlHTMLAttribute = escape(escapedDomainUrlJS);
+
+    // Escape the website id for use in an HTML attribute.
+    let escapedWebsiteIdHTMLAttribute = escape(escapedWebsiteIdJS);
+
+    return `
+        <script defer src="https://${escapedDomainUrlHTMLAttribute}/script.js" data-website-id="${escapedWebsiteIdHTMLAttribute}"></script>
+    `;
+}
+
+module.exports = {
+    getUmamiAnalyticsScript,
+};
diff --git a/server/model/status_page.js b/server/model/status_page.js
index 38f548ebb..32188ffaa 100644
--- a/server/model/status_page.js
+++ b/server/model/status_page.js
@@ -3,7 +3,7 @@ const { R } = require("redbean-node");
 const cheerio = require("cheerio");
 const { UptimeKumaServer } = require("../uptime-kuma-server");
 const jsesc = require("jsesc");
-const googleAnalytics = require("../google-analytics");
+const analytics = require("../analytics/analytics");
 const { marked } = require("marked");
 const { Feed } = require("feed");
 const config = require("../config");
@@ -120,9 +120,9 @@ class StatusPage extends BeanModel {
 
         const head = $("head");
 
-        if (statusPage.googleAnalyticsTagId) {
-            let escapedGoogleAnalyticsScript = googleAnalytics.getGoogleAnalyticsScript(statusPage.googleAnalyticsTagId);
-            head.append($(escapedGoogleAnalyticsScript));
+        if (analytics.isValidAnalyticsConfig(statusPage)) {
+            let escapedAnalyticsScript = analytics.getAnalyticsScript(statusPage);
+            head.append($(escapedAnalyticsScript));
         }
 
         // OG Meta Tags
@@ -407,7 +407,9 @@ class StatusPage extends BeanModel {
             customCSS: this.custom_css,
             footerText: this.footer_text,
             showPoweredBy: !!this.show_powered_by,
-            googleAnalyticsId: this.google_analytics_tag_id,
+            analyticsId: this.analytics_id,
+            analyticsDomainUrl: this.analytics_domain_url,
+            analyticsType: this.analytics_type,
             showCertificateExpiry: !!this.show_certificate_expiry,
         };
     }
@@ -430,7 +432,9 @@ class StatusPage extends BeanModel {
             customCSS: this.custom_css,
             footerText: this.footer_text,
             showPoweredBy: !!this.show_powered_by,
-            googleAnalyticsId: this.google_analytics_tag_id,
+            analyticsId: this.analytics_id,
+            analyticsDomainUrl: this.analytics_domain_url,
+            analyticsType: this.analytics_type,
             showCertificateExpiry: !!this.show_certificate_expiry,
         };
     }
diff --git a/server/socket-handlers/status-page-socket-handler.js b/server/socket-handlers/status-page-socket-handler.js
index 1114d81fd..60957d49d 100644
--- a/server/socket-handlers/status-page-socket-handler.js
+++ b/server/socket-handlers/status-page-socket-handler.js
@@ -166,7 +166,9 @@ module.exports.statusPageSocketHandler = (socket) => {
             statusPage.show_powered_by = config.showPoweredBy;
             statusPage.show_certificate_expiry = config.showCertificateExpiry;
             statusPage.modified_date = R.isoDateTime();
-            statusPage.google_analytics_tag_id = config.googleAnalyticsId;
+            statusPage.analytics_id = config.analyticsId;
+            statusPage.analytics_domain_url = config.analyticsDomainUrl;
+            statusPage.analytics_type = config.analyticsType;
 
             await R.store(statusPage);
 
diff --git a/src/lang/en.json b/src/lang/en.json
index cb704b0fe..94deb0a81 100644
--- a/src/lang/en.json
+++ b/src/lang/en.json
@@ -787,6 +787,11 @@
     "wayToGetClickSendSMSToken": "You can get API Username and API Key from {0} .",
     "Custom Monitor Type": "Custom Monitor Type",
     "Google Analytics ID": "Google Analytics ID",
+    "Analytics Type": "Analytics Type",
+    "Analytics ID": "Analytics ID",
+    "Analytics Domain URL": "Analytics Domain URL",
+    "Umami Analytics Domain Url": "Umami Analytics Domain Url",
+    "Umami Analytics Website ID": "Umami Analytics Website ID",
     "Edit Tag": "Edit Tag",
     "Server Address": "Server Address",
     "Learn More": "Learn More",
diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue
index 116968282..8a35fef60 100644
--- a/src/pages/StatusPage.vue
+++ b/src/pages/StatusPage.vue
@@ -1,3 +1,29 @@
+<script setup>
+// Analytics options
+const analyticsOptions = [
+    {
+        name: "None",
+        value: null
+    },
+    {
+        name: "Google",
+        value: "google"
+    },
+    {
+        name: "Umami",
+        value: "umami"
+    },
+    {
+        name: "Plausible",
+        value: "plausible"
+    },
+    {
+        name: "Matomo",
+        value: "matomo"
+    }
+];
+</script>
+
 <template>
     <div v-if="loadedTheme" class="container mt-3">
         <!-- Sidebar for edit mode -->
@@ -92,10 +118,25 @@
                     </ul>
                 </div>
 
-                <!-- Google Analytics -->
+                <!-- Analytics -->
+
                 <div class="my-3">
-                    <label for="googleAnalyticsTag" class="form-label">{{ $t("Google Analytics ID") }}</label>
-                    <input id="googleAnalyticsTag" v-model="config.googleAnalyticsId" type="text" class="form-control" data-testid="google-analytics-input">
+                    <label for="analyticsType" class="form-label">{{ $t("Analytics Type") }}</label>
+                    <select id="analyticsType" v-model="config.analyticsType" class="form-select" data-testid="analytics-type-select">
+                        <option v-for="(analyticOption, index) in analyticsOptions" :key="index" :value="analyticOption.value">
+                            {{ analyticOption.name }}
+                        </option>
+                    </select>
+                </div>
+
+                <div v-if="config.analyticsType !== null && config.analyticsType !== undefined" class="my-3">
+                    <label for="analyticsId" class="form-label">{{ $t("Analytics ID") }}</label>
+                    <input id="analyticsId" v-model="config.analyticsId" type="text" class="form-control" data-testid="analytics-id-input">
+                </div>
+
+                <div v-if="config.analyticsType !== null && config.analyticsType !== undefined && config.analyticsType !== 'google'" class="my-3">
+                    <label for="analyticsDomainUrl" class="form-label">{{ $t("Analytics Domain URL") }}</label>
+                    <input id="analyticsDomainUrl" v-model="config.analyticsDomainUrl" type="text" class="form-control" data-testid="analytics-domain-url-input">
                 </div>
 
                 <!-- Custom CSS -->
diff --git a/test/e2e/specs/status-page.spec.js b/test/e2e/specs/status-page.spec.js
index f525dfc6f..e75f3c993 100644
--- a/test/e2e/specs/status-page.spec.js
+++ b/test/e2e/specs/status-page.spec.js
@@ -18,6 +18,12 @@ test.describe("Status Page", () => {
         const refreshInterval = 30;
         const theme = "dark";
         const googleAnalyticsId = "G-123";
+        const umamiAnalyticsDomainUrl = "example.com";
+        const umamiAnalyticsWebsiteId = "606487e2-bc25-45f9-9132-fa8b065aad46";
+        const plausibleAnalyticsDomainUrl = "example.com";
+        const plausibleAnalyticsDomainsUrls = "one.com,two.com";
+        const matomoUrl = "matomo.com";
+        const matomoSiteId = "123456789";
         const customCss = "body { background: rgb(0, 128, 128) !important; }";
         const descriptionText = "This is an example status page.";
         const incidentTitle = "Example Outage Incident";
@@ -57,7 +63,8 @@ test.describe("Status Page", () => {
         await page.getByTestId("show-tags-checkbox").uncheck();
         await page.getByTestId("show-powered-by-checkbox").uncheck();
         await page.getByTestId("show-certificate-expiry-checkbox").uncheck();
-        await page.getByTestId("google-analytics-input").fill(googleAnalyticsId);
+        await page.getByTestId("analytics-type-select").selectOption("google");
+        await page.getByTestId("analytics-id-input").fill(googleAnalyticsId);
         await page.getByTestId("custom-css-input").getByTestId("textarea").fill(customCss); // Prism
         await expect(page.getByTestId("description-editable")).toHaveText(descriptionText);
         await expect(page.getByTestId("custom-footer-editable")).toHaveText(footerText);
@@ -100,12 +107,12 @@ test.describe("Status Page", () => {
         expect(updateCountdown).toBeLessThanOrEqual(refreshInterval + 10);
 
         await expect(page.locator("body")).toHaveClass(theme);
-        expect(await page.locator("head").innerHTML()).toContain(googleAnalyticsId);
 
         const backgroundColor = await page.evaluate(() => window.getComputedStyle(document.body).backgroundColor);
         expect(backgroundColor).toEqual("rgb(0, 128, 128)");
 
         await screenshot(testInfo, page);
+        expect(await page.locator("head").innerHTML()).toContain(googleAnalyticsId);
 
         // Flip the "Show Tags" and "Show Powered By" switches:
         await page.getByTestId("edit-button").click();
@@ -114,6 +121,11 @@ test.describe("Status Page", () => {
         await page.getByTestId("show-powered-by-checkbox").setChecked(true);
 
         await screenshot(testInfo, page);
+
+        // Fill in umami analytics after editing
+        await page.getByTestId("analytics-type-select").selectOption("umami");
+        await page.getByTestId("analytics-domain-url-input").fill(umamiAnalyticsDomainUrl);
+        await page.getByTestId("analytics-id-input").fill(umamiAnalyticsWebsiteId);
         await page.getByTestId("save-button").click();
 
         await expect(page.getByTestId("edit-sidebar")).toHaveCount(0);
@@ -121,6 +133,29 @@ test.describe("Status Page", () => {
         await expect(page.getByTestId("monitor-tag")).toContainText(tagValue);
 
         await screenshot(testInfo, page);
+
+        expect(await page.locator("head").innerHTML()).toContain(umamiAnalyticsDomainUrl);
+        expect(await page.locator("head").innerHTML()).toContain(umamiAnalyticsWebsiteId);
+
+        await page.getByTestId("edit-button").click();
+        // Fill in plausible analytics after editing
+        await page.getByTestId("analytics-type-select").selectOption("plausible");
+        await page.getByTestId("analytics-domain-url-input").fill(plausibleAnalyticsDomainUrl);
+        await page.getByTestId("analytics-id-input").fill(plausibleAnalyticsDomainsUrls);
+        await page.getByTestId("save-button").click();
+        await screenshot(testInfo, page);
+        expect(await page.locator("head").innerHTML()).toContain(plausibleAnalyticsDomainUrl);
+        expect(await page.locator("head").innerHTML()).toContain(plausibleAnalyticsDomainsUrls);
+
+        await page.getByTestId("edit-button").click();
+        // Fill in matomo analytics after editing
+        await page.getByTestId("analytics-type-select").selectOption("matomo");
+        await page.getByTestId("analytics-domain-url-input").fill(matomoUrl);
+        await page.getByTestId("analytics-id-input").fill(matomoSiteId);
+        await page.getByTestId("save-button").click();
+        await screenshot(testInfo, page);
+        expect(await page.locator("head").innerHTML()).toContain(matomoUrl);
+        expect(await page.locator("head").innerHTML()).toContain(matomoSiteId);
     });
 
     // @todo Test certificate expiry