feat: 📈 add ackee analytics and privacy policy

This commit is contained in:
Sebin Nyshkim 2025-07-18 21:57:44 +02:00
parent 67a3efe4dc
commit 01587dd5b8
Signed by: SebinNyshkim
SSH key fingerprint: SHA256:LG1WHMySL/4iW/Yci+0eHgbf0te5beRiLlmyoY8E5D0
5 changed files with 97 additions and 1 deletions

View file

@ -51,6 +51,9 @@ export default async function (eleventyConfig) {
eleventyConfig.addPassthroughCopy('./src/fonts/'); eleventyConfig.addPassthroughCopy('./src/fonts/');
eleventyConfig.addWatchTarget('./src/fonts/'); eleventyConfig.addWatchTarget('./src/fonts/');
eleventyConfig.addPassthroughCopy('./src/js/');
eleventyConfig.addWatchTarget('./src/js/');
eleventyConfig.addCollection('posts', (collection) => eleventyConfig.addCollection('posts', (collection) =>
process.env.ELEVENTY_PRODUCTION process.env.ELEVENTY_PRODUCTION
? collection.getFilteredByGlob('./src/posts/*.md') ? collection.getFilteredByGlob('./src/posts/*.md')

View file

@ -11,6 +11,8 @@
--min-height-128: 32rem; --min-height-128: 32rem;
--min-height-160: 40rem; --min-height-160: 40rem;
--min-height-192: 48rem; --min-height-192: 48rem;
--width-128: calc(var(--spacing) * 128);
} }
:root { :root {

23
src/js/ackee.js Normal file
View file

@ -0,0 +1,23 @@
const ackeeBanner = document.querySelector('#ackee-banner');
const yesBtn = ackeeBanner.querySelector('#yes');
const noBtn = ackeeBanner.querySelector('#no');
const confirmKey = 'ackeeDetailed';
yesBtn.addEventListener('click', () => localStorage.setItem(confirmKey, true));
noBtn.addEventListener('click', () => localStorage.setItem(confirmKey, false));
if (localStorage.getItem(confirmKey) === null) {
ackeeBanner.show();
}
const ackeeServer = 'https://ackee.sebin-nyshkim.net';
const ackeeDomainId = 'c7d67b68-9522-4bf0-8dd5-1332790999a9';
const ackeeOpts = {
detailed: localStorage.getItem(confirmKey) === 'true',
ignoreLocalhost: false
};
if (localStorage.getItem(confirmKey) === 'true') {
const instance = ackeeTracker.create(ackeeServer, ackeeOpts);
instance.record(ackeeDomainId);
}

View file

@ -73,9 +73,12 @@
<p>Content licensed under <p>Content licensed under
<a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a> <a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a>
</p> </p>
<p>
<a href="/privacy">Privacy Policy</a>
</p>
</div> </div>
<div class="basis-full space-y-4 sm:text-right"> <div class="basis-full space-y-4 sm:text-right">
<p>Made with <a href="https://11ty.dev">11ty</a></p> <p>Made with ❤️ and <a href="https://11ty.dev">11ty</a></p>
<ul class="flex justify-start gap-4 sm:justify-end" aria-label="Connect"> <ul class="flex justify-start gap-4 sm:justify-end" aria-label="Connect">
<li> <li>
<a <a
@ -115,5 +118,24 @@
</div> </div>
</div> </div>
</footer> </footer>
<dialog id="ackee-banner" class="fixed start-4 end-4 top-auto ms-auto bottom-4 max-w-128 rounded-xl bg-sky-600 text-white shadow-xl dark:bg-sky-950">
<form method="dialog" class="flex flex-col">
<div class="space-y-4 p-4 text-center">
<p class="text-xl font-bold">Analytics</p>
<p>
I would like to know which devices my site is displayed on. May I collect data about your device? The specific data is outlined
<a href="/privacy" class="!decoration-white hover:!text-white dark:!decoration-sky-600 dark:hover:!text-sky-600">here</a>.
</p>
</div>
<div class="flex flex-row *:first:rounded-es-xl *:last:rounded-ee-xl *:first:border-e">
<button id="yes" class="flex-1/2 grow bg-sky-500 px-4 py-2 hover:bg-sky-800 dark:bg-sky-800 dark:hover:bg-sky-500">Yeah sure</button>
<button id="no" class="flex-1/2 grow bg-sky-500 px-4 py-2 hover:bg-sky-800 dark:bg-sky-800 dark:hover:bg-sky-500">Nope</button>
</div>
</form>
</dialog>
<script src="https://ackee.sebin-nyshkim.net/tracker.js"></script>
<script src="/js/ackee.js"></script>
</body> </body>
</html> </html>

46
src/privacy.md Normal file
View file

@ -0,0 +1,46 @@
---
layout: page.njk
---
# Privacy Policy
I use a self-hosted [Ackee](https://ackee.electerious.com) instance to gain insights about the types of devices that visit this site.
Ackee is open-source analytics software. The data it collects is anonymized in a way that does not allow me to identify individual visitors. It also does not save any cookies and does not follow you around the web. I merely store whether you agree to analytics collection or not in your browser's local storage.
## Data that Ackee collects
Ackee gives me insight into the following data points:
* Number of visits per day
* Number of visitors that currently view the site
* Approximate duration of stay
* Number of times a given page was visited
* Sites a visit originated from (referrer)
* Name and manufacturer of the device
* Name and version of the operating system
* Name and version of the browser
* Screen size of the device
* Primary language of the browser or operating system
Ackee uses the IP, user-agent and domainId to identify a user. All information will be hashed together with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) that changes daily. The final hash is called `clientId`.
The daily salt is never stored anywhere. It avoids that database backups can be used to stick data together to reconstruct the browsing history of a user.
## Purpose of collecting data
I collect this data to better understand my audience, improve the site's user experience, and to inform future development and editorial decisions. The data will not be shared with anyone, ever.
## Data retention
Ackee removes data from previous records when a new record with an existing identification gets added. This way the user identifier and other identifiable data is only stored once in the database.
In other words: Ackee forgets who you are as soon as it sees you again. It's not possible to reconstruct a browsing history, even on a daily basis.
## User consent
Data collection is opt-in. I will not collect any analytics data until you explicitly allow me to do so. If you previously opted-in but changed your mind, click the button below:
<button onclick="localStorage.setItem('ackeeDetailed', false)" class="items-center bg-sky-600 *:stroke-[2.5] 2xl:px-6 2xl:py-3 2xl:rounded-2xl button duration-300 font-bold gap-2 hover:bg-sky-700 inline-flex no-underline px-5 py-2 rounded-xl text-white transition-colors">Opt-out</button>
By using this site, you acknowledge that you have read and understood this privacy policy. If you have any questions or concerns about how your data is collected or used, please feel free to [contact me](/contact).