Privacy-First Analytics
Collect meaningful metrics without invasive tracking or unique identifiers. Fully GDPR, CCPA, and PECR compliant by design.
Aptabase is an open-source, privacy-first analytics platform designed specifically for mobile, desktop, and web applications. Unlike traditional analytics tools that rely on invasive tracking and unique identifiers, Aptabase focuses on session-based metrics while maintaining full compliance with GDPR, CCPA, and PECR regulations. With extensive SDK support for Swift, Kotlin, React Native, Flutter, Electron, Tauri, and many more frameworks, Aptabase provides developers with actionable insights without compromising user privacy.
This guide walks you through deploying a self-hosted Aptabase instance on Klutch.sh using Docker, complete with PostgreSQL for metadata storage and ClickHouse for high-performance event analytics.
Privacy-First Analytics
Collect meaningful metrics without invasive tracking or unique identifiers. Fully GDPR, CCPA, and PECR compliant by design.
Extensive SDK Support
Native SDKs for Swift, Kotlin, React Native, Flutter, Electron, Tauri, .NET MAUI, Unity, Unreal Engine, and more.
Simple Dashboard
Built-in, user-friendly dashboard provides essential metrics at a glance without overwhelming complexity.
100% Open Source
Complete transparency with AGPLv3 licensed server code and MIT licensed SDKs.
Before deploying Aptabase on Klutch.sh, ensure you have the following:
Aptabase uses a dual-database architecture:
┌─────────────────┐ ┌──────────────────┐ ┌────────────────┐│ Your Apps │────▶│ Aptabase │────▶│ PostgreSQL ││ (SDKs) │ │ (Port 8080) │ │ (Metadata) │└─────────────────┘ └──────────────────┘ └────────────────┘ │ │ ▼ ┌────────────────┐ │ ClickHouse │ │ (Events) │ └────────────────┘Create a Dockerfile in your project root that builds upon the official Aptabase image:
FROM ghcr.io/aptabase/aptabase:main
# Set the working directoryWORKDIR /app
# Expose the application portEXPOSE 8080
# The base image already includes the ENTRYPOINT# Environment variables will be configured through Klutch.shAptabase requires several environment variables for proper configuration. Configure these in the Klutch.sh dashboard:
| Variable | Description | Example |
|---|---|---|
BASE_URL | The public URL of your Aptabase instance | https://analytics.example-app.klutch.sh |
AUTH_SECRET | A strong random secret for signing auth tokens (32+ characters) | c4rI4x8kz5DgKJ1is5Eiu9bNncSQ6ROD |
DATABASE_URL | PostgreSQL connection string in .NET format | Server=host;Port=5432;User Id=user;Password=pass;Database=aptabase |
CLICKHOUSE_URL | ClickHouse connection string | Host=host;Port=8123;Username=user;Password=pass |
| Variable | Description | Example |
|---|---|---|
SMTP_HOST | SMTP server hostname | smtp.sendgrid.net |
SMTP_PORT | SMTP server port | 587 |
SMTP_USERNAME | SMTP authentication username | apikey |
SMTP_PASSWORD | SMTP authentication password | your-smtp-password |
SMTP_FROM_ADDRESS | Email sender address | noreply@yourdomain.com |
| Variable | Description |
|---|---|
OAUTH_GITHUB_CLIENT_ID | GitHub OAuth client ID |
OAUTH_GITHUB_CLIENT_SECRET | GitHub OAuth client secret |
OAUTH_GOOGLE_CLIENT_ID | Google OAuth client ID |
OAUTH_GOOGLE_CLIENT_SECRET | Google OAuth client secret |
First, deploy a PostgreSQL database as a separate Klutch.sh project:
FROM postgres:15-alpine
ENV POSTGRES_USER=aptabaseENV POSTGRES_PASSWORD=your-strong-passwordENV POSTGRES_DB=aptabase
EXPOSE 5432Deploy ClickHouse as another separate project:
FROM clickhouse/clickhouse-server:23.8.4.69-alpine
ENV CLICKHOUSE_USER=aptabaseENV CLICKHOUSE_PASSWORD=your-strong-password
EXPOSE 8123
# Increase file descriptor limits for ClickHouse performanceFor production deployments, consider using managed services:
PostgreSQL:
ClickHouse:
Your Aptabase project repository should have the following structure:
aptabase-deploy/├── Dockerfile└── README.mdPush your repository to GitHub
Create a new repository on GitHub and push your Dockerfile:
git initgit add .git commit -m "Initial Aptabase deployment configuration"git branch -M maingit remote add origin https://github.com/yourusername/aptabase-deploy.gitgit push -u origin mainConnect to Klutch.sh
Navigate to klutch.sh/app and sign in with your GitHub account. Click New Project to begin the deployment process.
Select your repository
Choose the GitHub repository containing your Aptabase Dockerfile. Klutch.sh will automatically detect the Dockerfile in your project root.
Configure environment variables
Add the required environment variables in the Klutch.sh dashboard:
BASE_URL - Your Aptabase instance URL (e.g., https://analytics.example-app.klutch.sh)AUTH_SECRET - A strong 32+ character random stringDATABASE_URL - PostgreSQL connection stringCLICKHOUSE_URL - ClickHouse connection stringSet the internal port
Configure the internal port to 8080 where Aptabase listens for HTTP traffic.
Add persistent storage (optional)
If you want to persist any local data, add a persistent volume:
| Mount Path | Size |
|---|---|
/app/data | 1 GB |
Deploy your application
Click Deploy to start the deployment process. Klutch.sh will build the Docker image and deploy your Aptabase instance.
After deployment, you’ll need to create your first account:
Access your Aptabase instance
Navigate to your deployed Aptabase URL (e.g., https://analytics.example-app.klutch.sh).
Register a new account
Click the registration link and enter your email address. Since SMTP may not be configured initially, you’ll need to find the activation link in your container logs.
Find the activation link
In your Klutch.sh dashboard, check the deployment logs to find the email activation link. Copy the link and paste it into your browser to activate your account.
Create your first app
Once logged in, create a new app in Aptabase to get your App Key. You’ll use this key to initialize the SDK in your applications.
Install the Aptabase SDK:
npm install @aptabase/react-nativeInitialize in your app:
import Aptabase from '@aptabase/react-native';
// Initialize with your App Key and custom hostAptabase.init('A-YOUR-APP-KEY', { host: 'https://analytics.example-app.klutch.sh'});
// Track an eventAptabase.trackEvent('app_started');
// Track with propertiesAptabase.trackEvent('button_clicked', { buttonName: 'submit', screenName: 'checkout'});Add to your pubspec.yaml:
dependencies: aptabase_flutter: ^0.0.8Initialize in your app:
import 'package:aptabase_flutter/aptabase_flutter.dart';
void main() async { WidgetsFlutterBinding.ensureInitialized();
await Aptabase.init( 'A-YOUR-APP-KEY', InitOptions(host: 'https://analytics.example-app.klutch.sh'), );
runApp(MyApp());}
// Track eventsAptabase.instance.trackEvent('app_started');Aptabase.instance.trackEvent('purchase_completed', { 'amount': 29.99, 'currency': 'USD',});Install the SDK:
npm install @aptabase/electronInitialize in your main process:
import { initialize, trackEvent } from '@aptabase/electron';
// Initialize with your App Keyinitialize('A-YOUR-APP-KEY', { host: 'https://analytics.example-app.klutch.sh'});
// Track eventstrackEvent('app_started');trackEvent('file_opened', { fileType: 'pdf' });Add to your Cargo.toml:
[dependencies]tauri-plugin-aptabase = "2"Configure in your Tauri app:
use tauri_plugin_aptabase::Builder;
fn main() { tauri::Builder::default() .plugin( Builder::new("A-YOUR-APP-KEY") .with_host("https://analytics.example-app.klutch.sh") .build(), ) .run(tauri::generate_context!()) .expect("error while running tauri application");}Install the SDK:
npm install @aptabase/webInitialize in your web app:
import { init, trackEvent } from '@aptabase/web';
// Initialize with your App Keyinit('A-YOUR-APP-KEY', { host: 'https://analytics.example-app.klutch.sh'});
// Track eventstrackEvent('page_view', { page: '/home' });trackEvent('signup_completed');To use a custom domain with your Aptabase deployment:
Add your domain in Klutch.sh
Navigate to your project settings in the Klutch.sh dashboard and add your custom domain (e.g., analytics.yourdomain.com).
Configure DNS records
Add a CNAME record pointing to your Klutch.sh deployment:
| Type | Name | Value |
|---|---|---|
| CNAME | analytics | example-app.klutch.sh |
Update BASE_URL
Update the BASE_URL environment variable in Klutch.sh to match your custom domain:
BASE_URL=https://analytics.yourdomain.comWait for SSL provisioning
Klutch.sh automatically provisions SSL certificates for custom domains. This may take a few minutes.
For local development and testing, you can use Docker Compose:
services: postgres: image: postgres:15-alpine restart: always volumes: - postgres-data:/var/lib/postgresql/data environment: POSTGRES_USER: aptabase POSTGRES_PASSWORD: local_dev_password POSTGRES_DB: aptabase ports: - "5432:5432"
clickhouse: image: clickhouse/clickhouse-server:23.8.4.69-alpine restart: always volumes: - clickhouse-data:/var/lib/clickhouse environment: CLICKHOUSE_USER: aptabase CLICKHOUSE_PASSWORD: local_dev_password ulimits: nofile: soft: 262144 hard: 262144 ports: - "8123:8123"
aptabase: image: ghcr.io/aptabase/aptabase:main restart: always depends_on: - postgres - clickhouse ports: - "8000:8080" environment: BASE_URL: http://localhost:8000 AUTH_SECRET: local_development_secret_key_32chars DATABASE_URL: Server=postgres;Port=5432;User Id=aptabase;Password=local_dev_password;Database=aptabase CLICKHOUSE_URL: Host=clickhouse;Port=8123;Username=aptabase;Password=local_dev_password
volumes: postgres-data: clickhouse-data:Start the local development environment:
docker-compose up -dAccess Aptabase at http://localhost:8000.
If you haven’t configured SMTP, account activation emails won’t be sent. Check your container logs in the Klutch.sh dashboard to find the activation link.
Verify your connection strings are in the correct .NET format:
PostgreSQL:
Server=hostname;Port=5432;User Id=username;Password=password;Database=aptabaseClickHouse:
Host=hostname;Port=8123;Username=username;Password=passwordEnsure your SDK is configured with the correct host parameter pointing to your self-hosted instance, not the default Aptabase cloud.
ClickHouse requires high file descriptor limits. If you’re deploying ClickHouse on Klutch.sh, ensure your container has adequate resources allocated.
After deploying Aptabase, consider: