Ackee Documentation

Self-hosted, Node.js based analytics tool for those who care about privacy.

4,719 stars JavaScript JavaScript 15 files ยท ~14,685 tokens #analytics#google-analytics#privacy#website-analytics
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy Ackee on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name ackee -p 3000:3000 --restart always electerious/ackee
Configured Services & Ports
โš™๏ธ ackee
image: electerious/ackee
๐Ÿ”Œ Ports: 3000:3000
โš™๏ธ mongo
image: mongo
docker-compose.yml
yaml (docker-compose.yml)
services:
  ackee:
    image: electerious/ackee
    container_name: ackee
    restart: always
    ports:
      - '3000:3000'
    environment:
      - ACKEE_MONGODB=mongodb://mongo:27017/ackee
    env_file:
      - .env
    depends_on:
      - mongo
  mongo:
    image: mongo
    container_name: mongo
    restart: always
    volumes:
      - ./data:/data/db

Technical Documentation: electerious/Ackee

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

Overview (`README.md`)

๐Ÿ‘‹ Introduction

Ackee is a self-hosted analytics tool that cares about privacy. We believe that you don't need to track every aspect of your visitors. Ackee keeps tracked data anonymized to avoid that users are identifiable, while still providing helpful insights. It's the right tool for everyone who doesn't need a full-featured marketing analytics platform like Google Analytics or Matomo.

  • Self-hosted: Ackee runs on your own server and is 100% open-source
  • Modern technologies: Lightweight Node.js and MongoDB architecture
  • Beautiful: Minimal and focused interface
  • No cookies: No unique user tracking and therefore no required cookie message
  • Events: Track button clicks, newsletter subscriptions and more
  • GraphQL API: Fully documented GraphQL API that allows you to build new tools upon Ackee

๐Ÿš€ Get started

Get Ackee up and runningโ€ฆ

And configure Ackee and your server correctlyโ€ฆ

Take a look at the FAQ if you have any questions left.

๐Ÿ“š Documentation

Documentation and guides are located in the /docs folder. Also take a look at the FAQ if you have any questions left.

API

Ackee features a GraphQL API that allows you to build custom tools upon Ackee. Everything you see in the UI is made from data delivered by the API.

Options

Ackee uses environment variables and supports .env files in the root of the project if you want to store all variables in one file. Options »

Miscellaneous

I am working hard on continuously developing and maintaining Ackee. Please consider making a donation to keep the project going strong and me motivated.

Articles


Overview (`docs/http/README.md`)

HTTP Files

This folder contains .http files for manually testing the Ackee GraphQL API. These files can be used with HTTP clients that support the .http file format, such as the REST Client extension for VS Code or IntelliJ IDEA's built-in HTTP client.

Files

File Description
tokens.http Login (create token) and logout (delete token)
domains.http Create, read, update, and delete domains
records.http Create and update tracking records
events.http Create, read, update, and delete events
actions.http Create and update event actions
permanent-tokens.http Create, read, update, and delete permanent tokens
facts.http Fetch domain facts (active visitors, views, durations)
domain-statistics.http Domain statistics: browsers, devices, durations, languages, pages, referrers, sizes, systems, views
event-statistics.http Event statistics: chart and list

Usage

  1. Start by running the createToken request in tokens.http to obtain an access token.
  2. When prompted for accessToken, enter the token id from the login response.
  3. Use the token for all authenticated requests.

Requests that create tracking data (records.http, actions.http) do not require authentication, as they represent client-side tracking calls.


API (`docs/API.md`)

API

Ackee features a GraphQL API that allows you to build custom tools upon Ackee. Everything you see in the UI is made from data delivered by the API.

Here are a few resources to help you get started with GraphQL:

Playground

Ackee uses Apollo Sandbox, an interactive, in-browser GraphQL IDE. It allows you to play and experiment with the API of Ackee.

Simply run Ackee with NODE_ENV set to development and visit the /api playground in your browser. You can do so by adding NODE_ENV=development to the environment of your docker-compose.yml or by using npm run dev. Only use this mode on your local machine as Ackee runs slower when in development mode.

Try the ๐Ÿ”ฎ live playground of the Ackee demo.

Authentication

Modifying domains or receiving aggregated data is only possible once you're authenticated. Only the creation of new data is possible without a token.

Creating a token

The following mutation returns a new token id that should be used for authentication. This is what happens in the UI when you submit your username and password.

graphql
mutation createToken($input: CreateTokenInput!) {
  createToken(input: $input) {
    payload {
      id
    }
  }
}
json
{
  "input": {
    "username": "admin",
    "password": "123456"
  }
}

The token is valid for one day and will be renewed on every request made with it. You can modify the TTL (time to live) in the options. Create a permanent token if you need a token that doesn't expire.

Use a token

Protected queries and mutations need to include the Authorization HTTP header. Replace tokenId with the token id from the previous step.

json
{
  "Authorization": "Bearer tokenId"
}

Creating a permanent token

Permanent tokens don't expire and are perfect for tools that run periodically in the background. In this case you want a token that is always valid so you don't have to enter your credentials over and over again.

You can create permanent tokens in the settings of Ackee or via the API. Creating a permanent token requires a valid Authorization header. This means that you can only create permanent tokens with a valid (non-permanent) token.

graphql
mutation createPermanentToken($input: CreatePermanentTokenInput!) {
  createPermanentToken(input: $input) {
    payload {
      id
    }
  }
}
json
{
  "input": {
    "title": "iOS widget"
  }
}

Use a permanent token

Using a permanent token is the same as using a (non-permanent) token.

Time Zone

It's sometimes necessary to know the time zone of the user to accurately group stats by day, month or year. We therefore recommend to include a Time-Zone header when requesting data. The time zone should be formatted as a tz database time zone string.

The time zone of the server will be used as a fallback.

json
{
  "Time-Zone": "Europe/Berlin"
}

Queries

Queries are used to receive data. Here are a few examples.

Get all domains

graphql
query getDomains {
  domains {
    id
    title
  }
}

Get a specific domain

graphql
query getDomain($id: ID!) {
  domain(id: $id) {
    id
    title
  }
}
json
{
  "id": "3b8bc3ed-cdcb-492a-bc6d-8d5b2746da0e"
}

Get facts of domains

graphql
query getDomainsFacts {
  domains {
    facts {
      activeVisitors
      averageViews {
        count
        change
      }
      averageDuration {
        count
        change
      }
      viewsToday
      viewsMonth
      viewsYear
    }
  }
}

Get statistics of domains

graphql
query getDomainsStatistics {
  domains {
    statistics {
      durations(interval: DAILY) {
        id
        value
        count
      }
      views(interval: YEARLY, type: UNIQUE) {
        id
        value
        count
      }
      languages(sorting: TOP) {
        id
        value
        count
        created
      }
      browsers(sorting: TOP, type: WITH_VERSION) {
        id
        value
        count
        created
      }
      devices(sorting: TOP, type: WITH_MODEL) {
        id
        value
        count
        created
      }
      pages(sorting: TOP) {
        id
        value
        count
        created
      }
      referrers(sorting: TOP, type: WITH_SOURCE) {
        id
        value
        count
        created
      }
      sizes(sorting: TOP, type: SCREEN_RESOLUTION) {
        id
        value
        count
        created
      }
      systems(sorting: TOP, type: NO_VERSION) {
        id
        value
        count
        created
      }
    }
  }
}

Get events

graphql
query getEvents {
  events {
    id
    title
    statistics {
      chart(interval: DAILY, type: TOTAL) {
        id
        value
        count
      }
      list(sorting: TOP, type: TOTAL) {
        id
        value
        count
      }
    }
  }
}

Mutations

Mutations are used to add, update or delete data. Here are a few examples.

Create a domain

graphql
mutation createDomain($input: CreateDomainInput!) {
  createDomain(input: $input) {
    payload {
      id
      title
    }
  }
}
json
{
  "input": {
    "title": "Domain Title"
  }
}

Delete a domain

graphql
mutation deleteDomain($id: ID!) {
  deleteDomain(id: $id) {
    success
  }
}
json
{
  "id": "3b8bc3ed-cdcb-492a-bc6d-8d5b2746da0e"
}

Create a record

graphql
mutation createRecord($domainId: ID!, $input: CreateRecordInput!) {
  createRecord(domainId: $domainId, input: $input) {
    payload {
      id
    }
  }
}
json
{
  "domainId": "3b8bc3ed-cdcb-492a-bc6d-8d5b2746da0e",
  "input": {
    "siteLocation": "https://example.com"
  }
}

Create an event

graphql
mutation createEvent($input: CreateEventInput!) {
  createEvent(input: $input) {
    payload {
      id
      title
    }
  }
}
json
{
  "input": {
    "title": "Event Title",
    "type": "TOTAL_CHART"
  }
}

Create an action

graphql
mutation createAction($eventId: ID!, $input: CreateActionInput!) {
  createAction(eventId: $eventId, input: $input) {
    payload {
      id
    }
  }
}
json
{
  "eventId": "c8865d94-9077-420f-86a0-32545bcbf61b",
  "input": {
    "key": "Action Key",
    "value": 1
  }
}

Update an action

graphql
mutation updateAction($id: ID!, $input: UpdateActionInput!) {
  updateAction(id: $id, input: $input) {
    success
  }
}
json
{
  "id": "34df5a09-498f-45c1-822c-6b1f80de5f8c",
  "input": {
    "key": "Action Key",
    "value": null
  }
}

Anonymization (`docs/Anonymization.md`)

Anonymization

Ackee tries its best to keep tracked data anonymized. Several steps are used to avoid that users are identifiable, while still providing helpful analytics.

User identifier

Ackee uses the IP, user-agent and domainId to identify a user. All information will be hashed together with a salt 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.

Ackee also removes personal 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. Or with 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.

Personal data

Ackee won't track personal information by default, but it has the ability to do so in a privacy focused way. Our recommendation:

  1. Ask the user for permission to track personal data and set a cookie to remember their decision
  2. Enable detailed with the next page view (an option of ackee-tracker)
  3. Ackee now receives data considered as "personal data"

The following data is considered as "personal data":

Name Description
siteLanguage Language version of the browser.
screenWidth The width of the screen in pixels.
screenHeight The height of the screen in pixels.
screenColorDepth The bit depth of the color palette for displaying images (in bits per pixel).
deviceName The name of the product hosting the browser.
deviceManufacturer The name of the product's manufacturer.
osName The family of the OS.
osVersion The version of the OS.
browserName The name of the browser/environment.
browserVersion The browser/environment version.
browserWidth The width of the screen in pixels.
browserHeight The height of the screen in pixels.

All those parameters are considered as personal data, because you could point at the tracked person when sitting in the same room (even when this is probably never the case and totally unrealistic).

siteReferrer and visit duration (calculated using the creation and update time of a record) is not considered as personal data as you won't be able to identify a user with this piece of information. Even when you are in the same room you would need access to the browsing history of the user.


CORS Headers (`docs/CORS headers.md`)

CORS headers

Ackee requires correct CORS headers. ackee-tracker (the script that sends data from your sites to Ackee) won't be able to contact your server when the CORS headers aren't available or when they are configured incorrectly.

Why?

When a site wants to send data to a different domain it needs the permissions to do so. Browsers use an OPTIONS request (preflight request) that checks to see if the CORS protocol is understood.

Reverse proxy configuration

text
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PATCH, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, Time-Zone
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600

Origin

The Access-Control-Allow-Origin header only allows one domain. A wildcard (*) isn't recommended as it's neither a secure solution nor does it allow Ackee to ignore your own visits. Take a look at our recommended configuration if you want to allow requests from multiple domains or disable the ignoreOwnVisits option in ackee-tracker if using a wildcard is the only option for you.

text
Access-Control-Allow-Origin: https://example.com

Methods

ackee-tracker needs the permission to send GET, POST, PATCH and OPTIONS requests to the server.

text
Access-Control-Allow-Methods: GET, POST, PATCH, OPTIONS

Headers

The Access-Control-Allow-Headers header is used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.

text
Access-Control-Allow-Headers: Content-Type, Authorization, Time-Zone

Credentials

The Access-Control-Allow-Credentials header tells the browser to include the ackee_ignore cookie in requests even when you're on a different (sub-)domain. This allows Ackee to ignore your own visits.

โ„น๏ธ Some browsers strictly block third-party cookies when Ackee runs on a different domain than the site you're visiting. Therefore, it may happen that your own visits still find their way into your statistics.

text
Access-Control-Allow-Credentials: true

Max-Age

The Access-Control-Max-Age header tells the browser that all Access-Control-Allow-* headers can be cached for one hour. This minimizes the amount of preflight requests.

text
Access-Control-Max-Age: 3600

Platforms-As-A-Service configuration

If you are running Ackee on a platform which handles SSL for you, you may want a quick solution for setting CORS headers instead of using a reverse proxy.

As an environment variable, you will need to set:

text
ACKEE_ALLOW_ORIGIN=https://example.com

or

text
ACKEE_ALLOW_ORIGIN=https://example.com,https://one.example.com,https://two.example.com

Setting a wildcard (*) is also supported, but not recommended. It's neither a secure solution nor does it allow Ackee to ignore your own visits. Please disable the ignoreOwnVisits option in ackee-tracker if using a wildcard is the only option for you.

text
ACKEE_ALLOW_ORIGIN=*

Enhancing Referrers (`docs/Enhancing referrers.md`)

Enhancing referrers

Manually setting referrers

Whenever you post a link, you can choose to add a special query parameter to the link. When the ?source=<value> query parameter is present, Ackee will treat it as a referrer.

For example, here's what you can do when you want to send a newsletter to your subscribers. If you link to your site with example.com, anyone who clicks on it wouldn't show up under "Referrers".

But if you link to example.com?source=Newsletter anyone who clicks on that link will show "Newsletter" as the referrer source. This will allow you to see how many people have clicked on your link in the newsletter.

Fallback referrer

The Referer request header contains the address of the page making the request. It's not available in all situations (e.g. when opening a link from an application). Ackee will use and show the header in the UI when no source parameter is available.


Events (`docs/Events.md`)

Events

With Events, you can track button clicks, newsletter subscriptions, followers and more.

Privacy disclaimer

Ackee won't track personal information by default, but tracked events might either contain personal behavior patterns or data related to individual users. It's therefore recommended to ask the user for permission before tracking events.

Usage

Creating events

Create a new event in the settings of Ackee and you're ready to go. Ackee shows the id and a usage example when you click on an existing event. You can use the code to get started or by taking a look at the documentation of ackee-tracker.

Event type

The event type specifies how Ackee will show the aggregated data in the UI. It can be changed at any time.

  • Chart with total sums: Shows the aggregated data as a chart. Each day, month or year (depending on the chosen interval) includes the total sum of values.
  • Chart with average values: Shows the aggregated data as a chart. Each day, month or year (depending on the chosen interval) includes the average value.
  • List with total sums: Shows the aggregated data as a list. Each entry includes the total sum of values. Perfect when an event contains different actions (e.g. tracking choices).
  • List with average values: Shows the aggregated data as a list. Each entry includes the average value. Perfect when an event contains different actions (e.g. tracking choices).

Adding actions

An action should be added to an event whenever the user does what you want to track. It's similar to domains that get filled with records. You can add an action to an event using the GraphQL API or using ackee-tracker. An action creation can be triggered by anything that executes JS.

Setup:

js
import * as ackeeTracker from 'ackee-tracker'

const instance = ackeeTracker.create('https://ackee.example.com')

Examples:

js
document.querySelector('#newsletter').addEventListener('click', () => {
  instance.action('1b6e20cb-7c7d-48ca-8cb6-958a55d7a9e3', {
    key: 'Subscription',
    value: 1,
  })
})
js
document.querySelector('#buy').addEventListener('click', () => {
  instance.action('513a082c-2cd5-4939-b417-72da2fe1761d', {
    key: 'Checkout',
    value: parseFloat(document.querySelector('#price')),
  })
})
js
setTimeout(() => {
  instance.action('b7e1e5c9-e0a5-470e-bba0-ad8a295a3cfc', {
    key: 'User on site for 5sec',
    value: 1,
  })
}, 5000)

Updating actions

It's possible to update existing actions (e.g. when the user cancels a multi-step process). Doing so requires the actionId which can be obtained by a callback in the .action function.

js
let actionId

instance.action(
  '1b6e20cb-7c7d-48ca-8cb6-958a55d7a9e3',
  {
    key: 'Subscription',
    value: 1,
  },
  (_actionId) => {
    actionId = _actionId
  },
)

You can then use the actionId to change both key and value. Even resetting an action value is possible by setting the value to null.

js
instance.updateAction(actionId, {
  key: 'Subscription',
  value: null,
})

FAQ (`docs/FAQ.md`)

FAQ

Basics

How does it work?

You run the Ackee server which then waits for requests through its API.

The API of Ackee accepts information about your visitors sent to it using ackee-tracker. It's a small script you add to your sites, similar to the JavaScript tracking snippet provided by Google Analytics.

The interface of Ackee lets you view and analyze your tracked information.

Features

Can I import my nginx logs?

Ackee uses a JS snippet to aggregate data. Nginx logs won't work, but it might be possible to use the API of Ackee to build a custom import script.

Does Ackee support multiple user-accounts?

Ackee only works with one user and it's not planned to add support for multiple user-accounts. Ackee is however lightweight enough to create one Ackee instance per user. All instances can be connected to the same MongoDB.

Configuration

How to reset my password?

You can change the username and password environment variables whenever you want. Just make sure you restart Ackee after changing those.

How to reset my account?

There's no "account" in Ackee. Just delete your database or switch to a different one.

Comparison

How does Ackee compare to Matomo (Piwik)?

Matomo is more like Google Analytics in the way it works and what you can do with it. Ackee will never be a replacement if you are looking for a full-featured marketing analytics platform with tons of options and insights. Ackee tries to be less. Lightweight, easy to install and with a good balance between analytics and privacy.

Ackee is the right tool for you if Matomo offers more than you need and when you put a focus on the privacy of your users.

How does Ackee compare to Fathom?

Ackee and Fathom are very similar. Both in the way they display data and how they process it. The biggest advantages at the moment of writing:

  • Ackee is free and open-source
  • Ackee offers a documented GraphQL API that lets you build upon it. The API can be used for custom import scripts or apps that display your current visitor stats in the menu bar. The possibilities are endless.
  • Ackee allows you to track more than just page/site views (browser, system, etc.). This is optional and off by default, but great for people/companies that need more insights.

Definitions

What is a unique site view?

Each user increases the unique site view counter when visiting a domain for the first time a day.

Examples:

  • User visits three pages of a domain => The count increases by one
  • The same user visits your page at the end of the day => The count won't increase because the user is a returning user
  • The same user visits two pages on the next day => The count increases by one because new day = new user

What are total page views?

Each visit or reload of a page will increase the total page views counter.

Examples:

  • User views three pages of a domain => The count increases by three
  • User reloads the same page two times => The count increases by three (initial visit + first reload + second reload)

Are page views unique?

No, the views aren't unique, because Ackee can't track returning users for individual pages. This is because Ackee isn't storing a browsing history of your users.

Examples:

  • User visits three pages of a domain => The count of each page increases by one
  • User reloads the same page two times => The count of the page increases by three (initial visit + first reload + second reload)

Get Started (`docs/Get started.md`)

Get started

Ackee is a simple analytics tool that consists of two parts:

  1. A node server running on a server of your choice
  2. A tracking script that talks to that server

The node server shows you the UI and receives the request from all of your sites, while the tracking script is set up on each site you want to analyze. Since normally your site and your analytics server are running on the same machine, a subdomain is recommended to proxy all requests from that subdomain to the node server. The following guides help you to set up Ackee on an infrastructure of your choice.

With Docker Compose

1. Create the configuration

Pull the project and create a .env file in the root to store all environment variables in one file.

text
ACKEE_USERNAME=username
ACKEE_PASSWORD=password

Only those two are required to run Ackee with the existing docker-compose.yml. Take a look at the options for a detailed explanation.

2. Run Ackee

Run this command in the root of the project to use the predefined docker-compose.yml. It contains everything you need, including MongoDB and Ackee.

sh
docker-compose up

๐Ÿ’ก Add the -d flag to the Docker command to run the services in the background.

3. Open Ackee

Ackee will output the URL it's listening on once the server is running. Visit the URL with your browser and complete the final steps using the interface.

4. Get Ackee online

Ackee now runs on port 3000 and is only accessible from your local network. It's recommended to use a reverse proxy in front of Ackee. The following guides will help you through these steps.

With Docker

1. Setup MongoDB

Ackee requires a running MongoDB instance. The easiest way to install MongoDB is by using Docker. Skip this step if you have MongoDB installed or visit the website of MongoDB for alternative setups.

sh
docker run -p 27017:27017 --name mongo mongo

For persistent storage, mount a host directory to the container directory /data/db, which is identified as a potential mount point in the mongo Dockerfile. When starting a new container, Docker will use the volume of the previous container and copy it to the new container, ensuring that no data gets lost.

sh
docker run -p 27017:27017 -v /path/to/local/folder:/data/db --name mongo mongo

๐Ÿ’ก Add the -d flag to the Docker command to run MongoDB in the background.

Explanation:

  • -p makes port 27017 available at port 27017 on the host
  • -v mounts /path/to/local/folder to /data/db of the container
  • --name sets the container name to mongo
  • mongo is the name of the image

2. Run Ackee

sh
docker run -p 3000:3000 -e ACKEE_MONGODB='mongodb://mongo:27017/ackee' -e ACKEE_USERNAME='username' -e ACKEE_PASSWORD='password' --link mongo --name ackee electerious/ackee

๐Ÿ’ก Add the -d flag to the Docker command to run Ackee in the background.

Explanation:

  • -p makes port 3000 available at port 3000 on the host
  • -e sets environment variables required by Ackee
  • --link links Ackee with the mongo container
  • --name sets the container name to ackee
  • electerious/ackee is the name of the image

3. Open Ackee

Ackee will output the URL it's listening on once the server is running. Visit the URL with your browser and complete the final steps using the interface.

4. Get Ackee online

Ackee now runs on port 3000 and is only accessible from your local network. It's recommended to use a reverse proxy in front of Ackee. The following guides will help you through these steps.

With Helm

1. Create `values.yaml`

Based on the default values.yaml create your own with overrides as needed.

2. Deploy with `helm`

text
helm repo add suda https://suda.github.io/charts/
helm repo update
helm install ackee-release suda/ackee -n ackee -f values.yaml

If you're using the ingress-nginx, enabling the ingress will set the necessary annotations to enable CORS.

Without Docker

1. Install dependencies

Ackee depends on โ€ฆ

Make sure to install and update all dependencies before you continue. The installation instructions for the individual dependencies can be found on the linked websites.

2. Create the configuration

Pull the project and configure Ackee using environment variables or create a .env file in the root of the project to store all variables in one file.

text
ACKEE_MONGODB=mongodb://localhost:27017/ackee
ACKEE_USERNAME=username
ACKEE_PASSWORD=password

Only those three are required to run Ackee. Take a look at the options for a detailed explanation.

The MongoDB connection string is used to connect to your MongoDB. It should also contain the username and password of your MongoDB instance when required.

The username and password variables are used to secure your Ackee interface/API.

3. Install Ackee

Install all required dependencies.

sh
npm install

4. Run Ackee

Ackee will output the URL it's listening on once the server is running. Visit the URL with your browser and complete the final steps using the interface.

sh
npm run start

5. Get Ackee online

Ackee now runs on port 3000 and is only accessible from your local network. It's recommended to use a reverse proxy in front of Ackee. The following guides will help you through these steps.

With Netlify

1. Deploy to Netlify

2. Configure Ackee

  • You need to have a MongoDB instance running (e.g. MongoDB Atlas)
  • Set a username and password to protect your interface
  • Ensure that you're using the correct CORS headers by setting ACKEE_ALLOW_ORIGIN.

3. Updating Ackee

Netlify adds a forked version of Ackee to your GitHub repositories. You can always pull the newest code from the original project. Pushing those changes to your repository will automatically deploy the new version of Ackee on Netlify.

With Vercel

1. Deploy to Vercel

When prompted to select a directory, select the root directory.

2. Configure Ackee

  • Set the build command: npm run build
  • Set the output directory: dist
  • Set environment variables ACKEE_USERNAME, ACKEE_PASSWORD, ACKEE_MONGODB, and ACKEE_ALLOW_ORIGIN.

3. Updating Ackee

Vercel adds a forked version of Ackee to your GitHub repositories. You can always pull the newest code from the original project. Pushing those changes to your repository will automatically deploy the new version of Ackee on Vercel.

With Heroku

1. Deploy to Heroku

Deploy to Heroku by clicking this button:

2. Configure Ackee

  • You need to have a MongoDB instance running, either hosting it yourself, using MongoDB Atlas or by using a (paid) add-on like ObjectRocket MongoDB. This is as simple as typing heroku addons:create ormongo:2-wt --app <YOUR_APP_NAME> using the CLI, or using the web dashboard; more details at the official documentation. You'll need to provide connection details to Ackee dyno, either from the web dashboard or via command line, e.g. heroku config:add "ACKEE_MONGODB=mongodb://<host>:/<db>"
  • Ensure that you're using the correct CORS headers by setting ACKEE_ALLOW_ORIGIN.

3. Updating Ackee

The easiest way to update Ackee once hosted on Heroku is to clone the repo down, pull the latest changes from Ackee, and then push them back up to Heroku. You'll need the Heroku CLI and Git for this to work.

In your application view, you'll find instructions under the Deploy tab on how to clone down the project. It should look something like below:

sh
heroku login
heroku git:clone -a <your ackee application name>

You'll then want to add the Ackee repo as origin, pull the latest changes, and push it back up to Heroku.

sh
git remote add origin https://github.com/electerious/Ackee.git
git pull origin master
git push heroku master

After your application re-deploys you'll have the latest version of Ackee!

With Qovery

Qovery is a fully-managed cloud platform that runs on your AWS, GCP, Azure and Digital Ocean account where you can host static sites, backend APIs, databases, cron jobs, and all your other apps in one place.

1. Create a Qovery account.

Visit the Qovery dashboard to create an account if you don't already have one.

2. Create a project

Click on "Create a new project" and give a name to your project.

3. Add an application

Click on "Create an application" then choose "I have an application" and select your GitHub or GitLab repository where your Ackee app is located.

Select "MongoDB" service then choose a version. Give the database a name and continue with "Next".

Click on "Deploy".

Chat with Qovery developers on Discord if you need help.

With Render

You can use Render's one-click deploy button to get up and running with Ackee in minutes.

Click Deploy to Render below and follow the prompts to set up Ackee on Render.

Once your deploy has finished, you are ready to start using Ackee! Visit the URL for your service to login. You can get your login credentials from the ACKEE_USERNAME and ACKEE_PASSWORD environment variables in the Environment tab of your service. By default, your username will be render and your password will be a randomly generated string.

With Railway

You can use the button below for a one-click deployment and have Ackee running within minutes. Make sure you are logged into your Railway account, then follow the steps below.

1. Launch the Template

Launch the Ackee template on Railway by clicking this button:

2. Configure and Deploy

Upon launching the template, you will be prompted to configure the Ackee and MongoDB services.

  • Click Configure on the Ackee service and enter your desired username in the ACKEE_USERNAME environment variable input. Click Save Config.
    • Note: A password will be automatically generated for you which you can retrieve from within the Ackee service's variables tab after deployment.
  • Click Configure on the MongoDB service. You do not need to set any variable configurations, simply click Save Config.
  • Click Deploy

Upon deployment, everything should just work on its own. Railway will automatically provision the MongoDB database for you and link it to your Ackee service!

With Koyeb

Koyeb is a developer-friendly serverless platform to deploy apps globally. The platform lets you seamlessly run Docker containers, web apps, and APIs with git-based deployment, native autoscaling, free SSL, a global edge network, and built-in service mesh and discovery.

1. Configure Ackee

  • You need to have a MongoDB instance running (e.g. MongoDB Atlas)
  • Ensure that you're using the correct CORS headers by setting ACKEE_ALLOW_ORIGIN
  • Have the Koyeb CLI installed which is the fastest way to deploy Ackee

2. Deploy Ackee

Before deploying Ackee on Koyeb, create three secrets to securely store your Ackee username, password, and your MongoDB URL.
In your terminal execute the following to create the secrets:

sh
$ koyeb secret create mongodb-url
โœ” Enter your secret: mongodb://<username>:<password>@<host>:<port>/<db>

$ koyeb secret create ackee-username
โœ” Enter your secret: <ackee_username>

$ koyeb secret create ackee-password
โœ” Enter your secret: <ackee_password>

Once youโ€™ve created the secrets, you can deploy Ackee. In your terminal run the following command to create a new Koyeb App and deploy the Ackee service.

sh
koyeb app init ackee --docker electerious/ackee --ports 3000:http --routes /:3000 --env ACKEE_USERNAME=@ackee-username --env ACKEE_PASSWORD=@ackee-password --env ACKEE_MONGODB=@mongodb-url --env ACKEE_ALLOW_ORIGIN="https://example.com"

Your Ackee service is being deployed. To retrieve the Ackee URL run:

text
$ koyeb app get ackee
ID                                  	NAME     	DOMAINS                         	UPDATED AT
30de8301-05b1-4131-a842-28e608900000	ackee   	ackee-<YOUR_KOYEB_ORG>.koyeb.app	2021-07-06 11:58:01.143967 +0000 UTC

Open the URL to access Ackee.

With Zeabur

You can use the Zeabur button for a one-click deployment and have Ackee running within minutes.

Upon clicking the button, you will be asked to set the ACKEE_USERNAME environment variables. Once you do that, everything should just work on its own.
Zeabur will automatically provision the MongoDB database for you and also link it to your Ackee deployment!


Keyboard Shortcuts (`docs/Keyboard shortcuts.md`)

Keyboard shortcuts

Switch between views

In Ackee, you can quickly switch between views using the following keyboard shortcuts.

Key View
o Overview
0โ€ฆ9 Domain
v Views
p Pages
r Referrers
d Durations
e Events
s Settings

Interact with modals

The following keys are supported when a modal is focused.

Key Action
enter Confirm modal
esc Close modal

Options (`docs/Options.md`)

Options

The following environment variables are used by Ackee. You can also create a .env file in the root of the project to store all variables in one file. Ackee uses Node.js native --env-file support.

Database

MongoDB connection URI. See the MongoDB connection string spec for more detail.

text
ACKEE_MONGODB=mongodb://localhost:27017/ackee

or

text
MONGODB_URI=mongodb://localhost:27017/ackee

Port

The port Ackee should listen on. Defaults to 3000.

text
ACKEE_PORT=3000

or

text
PORT=3000

Username and password

Username and password. Both are required to generate a new token.

text
ACKEE_USERNAME=username
ACKEE_PASSWORD=password

TTL

Specifies how long a generated token is valid. Defaults to 86400000 (1 day).

text
ACKEE_TTL=86400000

Tracker

Pick a custom name for the tracking script of Ackee to avoid getting blocked by browser extensions. The default script will always be available via /tracker.js. Your custom script will be available via /custom%20name.js. Ackee will encode your custom name to a URL encoded format. Avoid characters that can't be used in filenames.

Make sure to adjust the tracking script URL on your sites when changing this option. Sites that are using the default URL won't be affected.

text
ACKEE_TRACKER=custom name

Environment

Set the environment to development to see additional error details and enable Apollo Sandbox. UI assets rebuilt with npm run build:pre will be unminified in this mode.

text
NODE_ENV=development

Demo mode

Set to true to enable demo mode. In demo mode, mutations that change domains, events, or permanent tokens are blocked, and Apollo Sandbox is enabled. Visitor tracking and login/logout remain available.

text
ACKEE_DEMO=true

CORS headers

Quick solution for setting CORS headers instead of using a reverse proxy. This is helpful if you are running Ackee on a platform that handles SSL for you.

text
ACKEE_ALLOW_ORIGIN=https://example.com

or

text
ACKEE_ALLOW_ORIGIN=https://example.com,https://one.example.com,https://two.example.com

Setting a wildcard (*) is also supported, but not recommended. It's neither a secure solution nor does it allow Ackee to ignore your own visits. Please disable the ignoreOwnVisits option in ackee-tracker if using a wildcard is the only option for you.

text
ACKEE_ALLOW_ORIGIN=*

As opposed to manually configuring CORS domains, you can also automatically add CORS Headers for domains in the domain list that have fully qualified domain names as titles. To achieve this, set:

text
ACKEE_AUTO_ORIGIN=true

Privacy Policy (`docs/Privacy Policy.md`)

Privacy Policy

Ackee is a privacy first product that keeps tracked data anonymized. It's therefore not required to mention Ackee in your privacy policy. Ackee doesn't store IP addresses or other personal identifiable information by default. It doesn't even use cookies, therefore, it doesn't need to be added to your cookie banner either.

However, we recommend to mention Ackee in your privacy policy. Let your visitors know that you're using a privacy friendly analytics tool which doesn't collect personal identifiable information.

โš ๏ธ Make sure to ask your users before activating the detailed mode of Ackee. The detailed mode tracks more data and also includes data we're considering as personal data. In this case it's highly recommended to add Ackee to your privacy policy.

HTML privacy policy example

html
To get information about the behavior of our visitors, we use
<a href="https://ackee.electerious.com" target="_blank" rel="noopener noreferrer">Ackee</a>. This analytics software
gives us insight about our visitors only in general, but not about individuals per se, as it does not track visitors and
does not store any personal identifiable information.
<a href="https://docs.ackee.electerious.com/#/docs/Anonymization" target="_blank" rel="noopener noreferrer"
  >Go to their documentation</a
>
to find out what Ackee collects.

Markdown privacy policy example

md
To get information about the behavior of our visitors, we use
[Ackee](https://ackee.electerious.com). This
analytics software gives us insight about our visitors only in general, but not
about individuals per se, as it does not track visitors and does not store any
personal identifiable information.
[Go
to their documentation](https://docs.ackee.electerious.com/#/docs/Anonymization) to find out what Ackee collects.

SSL And HTTPS (`docs/SSL and HTTPS.md`)

SSL and HTTPS

Ackee runs a simple server that doesn't support TLS/SSL. This means it's not possible to directly connect via HTTPS. It's recommended to use a reverse proxy instead. This document explains how.

What is a reverse proxy?

A reverse proxy is a type of proxy server that retrieves resources on behalf of a client from one or more servers. These resources are then returned to the client, appearing as if they originated from the proxy server itself.

A reverse proxy makes it easy for you to run Ackee on your server along with other services. It also allows you to secure connections using TLS/SSL.

I highly recommend this article if you want to learn more about reverse proxies.

Example configurations

nginx

This configuration redirects all requests to the non-www domain example.com, secures connections using TLS/SSL and allows CORS requests from a list of known domains.

๐Ÿ‘‰ The CORS headers are required so your sites can send data to Ackee, even when their domain is different to the one Ackee uses.

text
/* Detailed source-code truncated for AI context efficiency. */

Single domain configuration

This configuration secures all connections using TLS/SSL and allows https://example.com to send data to https://ackee.example.com.

โ„น๏ธ This configuration only allows requests from a single domain. Take a look at our recommended configuration if you want to allow requests from multiple domains or use the insecure wildcard configuration.

conf
server {
    listen 443 ssl http2;

    server_name ackee.example.com;

    ssl_certificate     /etc/letsencrypt/live/ackee.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ackee.example.com/privkey.pem;

    access_log /var/log/nginx/log/ackee.example.com.access.log main;
    error_log  /var/log/nginx/log/ackee.example.com.error.log;

    location / {
        add_header          Access-Control-Allow-Origin "https://example.com" always;
        add_header          Access-Control-Allow-Methods "GET, POST, PATCH, OPTIONS" always;
        add_header          Access-Control-Allow-Headers "Content-Type, Authorization, Time-Zone" always;
        add_header          Access-Control-Allow-Credentials "true" always;
        add_header          Access-Control-Max-Age "3600" always;
        add_header          Strict-Transport-Security "max-age=31536000" always;
        add_header          X-Frame-Options deny;
        proxy_pass          http://localhost:3000;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        proxy_redirect      off;
        proxy_buffering     off;
        proxy_set_header    Host $host;
        proxy_set_header    X-Real-IP $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Insecure wildcard configuration

A wildcard (*) isn't recommended as it's neither a secure solution nor does it allow Ackee to ignore your own visits. Please disable the ignoreOwnVisits option in ackee-tracker if using a wildcard is the only option for you.

conf
server {
    listen 443 ssl http2;

    server_name ackee.example.com;

    ssl_certificate     /etc/letsencrypt/live/ackee.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ackee.example.com/privkey.pem;

    access_log /var/log/nginx/log/ackee.example.com.access.log main;
    error_log  /var/log/nginx/log/ackee.example.com.error.log;

    location / {
        add_header          Access-Control-Allow-Origin "*" always;
        add_header          Access-Control-Allow-Methods "GET, POST, PATCH, OPTIONS" always;
        add_header          Access-Control-Allow-Headers "Content-Type, Authorization, Time-Zone" always;
        add_header          Access-Control-Max-Age "3600" always;
        add_header          Strict-Transport-Security "max-age=31536000" always;
        add_header          X-Frame-Options deny;
        proxy_pass          http://localhost:3000;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        proxy_redirect      off;
        proxy_buffering     off;
        proxy_set_header    Host $host;
        proxy_set_header    X-Real-IP $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Systemd (`docs/Systemd.md`)

Systemd

This guide shows you how to configure Ackee with systemd. We assume that your Ackee is located and installed in /opt/Ackee.

1. Make Ackee executable

Make the index.js executable with chmod +x /opt/Ackee/src/index.js.

2. Create the service

Create a file named ackee.service in /etc/systemd/system/.

text
[Unit]
Description=Ackee

[Service]
ExecStart=/opt/Ackee/src/index.js
Restart=always
User=nobody
Group=nogroup
Environment=PATH=/usr/bin:/usr/local/bin
Environment=NODE_ENV=production
WorkingDirectory=/opt/Ackee

[Install]
WantedBy=multi-user.target

3. Start the service

Start the service with systemctl start ackee.service and check if everything is up and running with systemctl status ackee.service.

4. Enable the service

Enable the service on boot with systemctl enable ackee.service.


Upgrade Guide (`docs/Upgrade guide.md`)

Upgrade guide

Upgrading from version 2 to 3

This change is relevant for you when using a wildcard as the Access-Control-Allow-Origin.

Using a wildcard (*) for the Access-Control-Allow-Origin header was never recommended as it's neither a secure solution nor does it allow Ackee to ignore your own visits. Please disable the ignoreOwnVisits option in ackee-tracker if you're currently using a wildcard. The SSL and HTTPS guide contains better alternatives.

ignoreOwnVisits is now enabled by default and won't work when using a wildcard.

New `Access-Control-Allow-Credentials` header

This change is relevant for everyone.

Ackee requires a new Access-Control-Allow-Credentials header which was previously optional. Make sure to add this header in your server or reverse proxy configuration.

ackee-tracker with new `.create` and `.record` syntax

This change is only relevant for you when using ackee-tracker in the Manually or Programmatic way.

The changelog of ackee-tracker contains everything you need to know when updating to the newest version.

Referrers require `ReferrerType` in GraphQL API

This change is relevant for you when using the GraphQL API.

A new parameter is required when requesting referrers via the GraphQL API. The parameter is called ReferrerType and can be WITH_SOURCE, NO_SOURCE or ONLY_SOURCE.

Referrers can return non URL ids via GraphQL API

This change is relevant for you when using the GraphQL API.

The id of requested referrers was always a URL, but has been changed to a string. That's because referrers can now include parameters (e.g. source when using ackee-tracker).


--- METRICS ---