diff --git a/astro.config.mjs b/astro.config.mjs
index b40751b..dc90792 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -3,6 +3,7 @@ import mdx from "@astrojs/mdx";
import sitemap from "@astrojs/sitemap";
import tailwind from "@astrojs/tailwind";
import solidJs from "@astrojs/solid-js";
+import matomo from "./src/integrations/matomo";
// https://astro.build/config
export default defineConfig({
@@ -13,5 +14,14 @@ export default defineConfig({
sitemap(),
solidJs(),
tailwind({ applyBaseStyles: false }),
+ matomo({
+ enabled: import.meta.env.PROD, // only enable in production
+ url: "https://analytics.hoelting.dev",
+ siteId: 3,
+ disableCookies: true,
+ enableCrossDomainLinking: true,
+ domains: ["*.hoelting.dev", "*.www.hoelting.dev"],
+ respectDoNotTrack: true,
+ }),
],
});
diff --git a/src/components/TwinklingStars.astro b/src/components/TwinklingStars.astro
index 3650379..d8ada99 100644
--- a/src/components/TwinklingStars.astro
+++ b/src/components/TwinklingStars.astro
@@ -7,54 +7,84 @@
*/
---
-
-
\ No newline at end of file
diff --git a/src/integrations/matomo/index.ts b/src/integrations/matomo/index.ts
new file mode 100644
index 0000000..4cd185d
--- /dev/null
+++ b/src/integrations/matomo/index.ts
@@ -0,0 +1,71 @@
+import type { AstroIntegration } from "astro";
+
+export type MatomoOptions = {
+ enabled: boolean;
+ url: string;
+ siteId: number;
+ trackerUrl?: string;
+ srcUrl?: string;
+ heartBeatTimer?: number;
+ setCookieDomain?: string;
+ disableCookies?: boolean;
+ preconnect?: boolean;
+ debug?: boolean;
+ respectDoNotTrack?: boolean;
+ domains?: string[];
+ enableCrossDomainLinking?: boolean;
+ customCampaignParameters?: {
+ name?: string;
+ keyword?: string;
+ };
+};
+
+export default function matomoIntegration(
+ options: MatomoOptions
+): AstroIntegration {
+ if (!options?.url.endsWith("/")) {
+ options.url += "/";
+ }
+
+ let script: string;
+
+ if (options?.enabled) {
+ script = `import { initMatomo, preconnectMatomo } from "@integrations/matomo/matomo"; initMatomo(${JSON.stringify(
+ options
+ )});`;
+
+ if (options?.preconnect) {
+ script += `preconnectMatomo(${JSON.stringify(options)});`;
+ }
+ } else {
+ console.info(
+ "\x1b[43m",
+ "Matomo",
+ "\x1b[0m",
+ "\x1b[34m",
+ "Is disabled.",
+ "\x1b[0m"
+ );
+
+ script = "";
+ }
+
+ return {
+ name: "matomo",
+ hooks: {
+ "astro:config:setup": async ({ injectScript }) => {
+ if (options?.enabled) {
+ injectScript("page", script);
+ console.info(
+ "\x1b[42m",
+ "Matomo",
+ "\x1b[0m",
+ "\x1b[34m",
+ "was integrated successfully.",
+ "\x1b[0m"
+ );
+ }
+ },
+ },
+ };
+}
diff --git a/src/integrations/matomo/matomo.ts b/src/integrations/matomo/matomo.ts
new file mode 100644
index 0000000..0ef98ea
--- /dev/null
+++ b/src/integrations/matomo/matomo.ts
@@ -0,0 +1,61 @@
+import type { MatomoOptions } from ".";
+
+export function initMatomo(options: MatomoOptions): void {
+ const _paq = (window._paq = window._paq || []);
+
+ if (options?.disableCookies) _paq.push(["disableCookies"]);
+ if (options?.heartBeatTimer)
+ _paq.push(["enableHeartBeatTimer", options.heartBeatTimer]);
+ if (options?.setCookieDomain)
+ _paq.push(["setCookieDomain", options.setCookieDomain]);
+ if (options?.respectDoNotTrack) _paq.push(["setDoNotTrack", true]);
+ if (options?.domains) _paq.push(["setDomains", options.domains]);
+ if (options?.enableCrossDomainLinking)
+ _paq.push(["enableCrossDomainLinking"]);
+ if (options?.customCampaignParameters?.name)
+ _paq.push([
+ "setCampaignNameKey",
+ options.customCampaignParameters.name,
+ ]);
+ if (options?.customCampaignParameters?.keyword)
+ _paq.push([
+ "setCampaignKeywordKey",
+ options.customCampaignParameters.keyword,
+ ]);
+
+ _paq.push(["trackPageView"]);
+ _paq.push(["enableLinkTracking"]);
+
+ if (options?.debug) {
+ console.warn("Matomo debug mode enabled!");
+ window._mtm = window._mtm || [];
+ window._mtm.push(["enableDebugMode"]);
+ }
+
+ (function () {
+ const u = options?.url;
+
+ _paq.push(["setTrackerUrl", u + (options?.trackerUrl || "matomo.php")]);
+ _paq.push(["setSiteId", options?.siteId]);
+
+ const d = document,
+ g = d.createElement("script"),
+ s = d.getElementsByTagName("script")[0];
+
+ g.id = "matomo-script";
+ g.type = "text/javascript";
+ g.async = true;
+ g.defer = true;
+ g.src = u + (options?.srcUrl || "matomo.js");
+ if (s.parentNode != null && u) s.parentNode.insertBefore(g, s);
+ })();
+}
+
+export function preconnectMatomo(options: MatomoOptions): void {
+ if (!options?.url) return;
+
+ const link = document.createElement("link");
+ link.rel = "preconnect";
+ link.href = options?.url;
+ document.head.appendChild(link);
+}
diff --git a/src/integrations/matomo/types/index.d.ts b/src/integrations/matomo/types/index.d.ts
new file mode 100644
index 0000000..557c54c
--- /dev/null
+++ b/src/integrations/matomo/types/index.d.ts
@@ -0,0 +1,8 @@
+export {};
+
+declare global {
+ interface Window {
+ _paq: Array;
+ _mtm: Array;
+ }
+}