How to Self-Host Countly with Docker Compose
What Is Countly?
Countly is an open-source product analytics platform that tracks web, mobile, and desktop application usage. Unlike simple pageview analytics like Plausible or Umami, Countly focuses on product metrics — user sessions, custom events, crash reporting, push notifications, and user flows. The Community Edition (AGPL-3.0) covers core analytics, while the Enterprise edition adds advanced features like funnels, cohorts, and A/B testing.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 4 GB of free RAM (MongoDB + Node.js workers)
- 10 GB of free disk space
- A domain name (recommended for production)
Docker Compose Configuration
Create a docker-compose.yml file:
services:
countly-api:
image: countly/api:25.03.39
container_name: countly-api
environment:
COUNTLY_PLUGINS: "mobile,web,desktop,plugins,density,locale,browser,sources,views,logger,systemlogs,populator,reports,crashes,push,star-rating,slipping-away-users,compare,server-stats,dbviewer,times-of-day,compliance-hub,alerts,onboarding,consolidate,remote-config,hooks,dashboards,sdk,data-manager"
COUNTLY_CONFIG__MONGODB_HOST: mongodb
COUNTLY_CONFIG_API_API_WORKERS: "4"
COUNTLY_CONFIG__FILESTORAGE: "gridfs"
NODE_OPTIONS: "--max-old-space-size=2048"
depends_on:
mongodb:
condition: service_healthy
networks:
- countly
restart: unless-stopped
countly-frontend:
image: countly/frontend:25.03.39
container_name: countly-frontend
environment:
COUNTLY_PLUGINS: "mobile,web,desktop,plugins,density,locale,browser,sources,views,logger,systemlogs,populator,reports,crashes,push,star-rating,slipping-away-users,compare,server-stats,dbviewer,times-of-day,compliance-hub,alerts,onboarding,consolidate,remote-config,hooks,dashboards,sdk,data-manager"
COUNTLY_CONFIG__MONGODB_HOST: mongodb
NODE_OPTIONS: "--max-old-space-size=2048"
deploy:
resources:
limits:
cpus: "0.5"
depends_on:
mongodb:
condition: service_healthy
networks:
- countly
restart: unless-stopped
mongodb:
image: bitnami/mongodb:7.0
container_name: countly-mongodb
volumes:
- mongodb_data:/bitnami
networks:
- countly
restart: unless-stopped
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
countly-nginx:
image: nginx:1.27-alpine
container_name: countly-nginx
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- countly-api
- countly-frontend
networks:
- countly
restart: unless-stopped
networks:
countly:
volumes:
mongodb_data:
Create nginx.conf for the reverse proxy:
upstream countly-api {
server countly-api:3001;
}
upstream countly-frontend {
server countly-frontend:6001;
}
server {
listen 80;
server_name _;
location = /i {
proxy_pass http://countly-api;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
location ^~ /i/ {
proxy_pass http://countly-api;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
location = /o {
proxy_pass http://countly-api;
}
location ^~ /o/ {
proxy_pass http://countly-api;
}
location / {
proxy_pass http://countly-frontend;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}
Start the stack:
docker compose up -d
Initial Setup
- Wait 1-2 minutes for MongoDB to initialize and Countly to start
- Open
http://your-server-ip:8080in your browser - Complete the setup wizard:
- Create an admin account (email and password)
- Enter your application name
- Select the platform (web, mobile, desktop)
- You’ll receive an app key and SDK endpoint URL
Configuration
API Workers
Set COUNTLY_CONFIG_API_API_WORKERS to match your CPU core count. More workers handle more concurrent requests:
| CPU Cores | Recommended Workers |
|---|---|
| 1-2 | 2 |
| 4 | 4 |
| 8+ | 6-8 |
Memory Allocation
NODE_OPTIONS: "--max-old-space-size=2048" sets Node.js heap to 2 GB. Adjust based on available RAM:
| Server RAM | Recommended Setting |
|---|---|
| 4 GB | 1024 |
| 8 GB | 2048 |
| 16 GB+ | 4096 |
Plugins
The COUNTLY_PLUGINS environment variable controls which plugins load. The list in the Docker Compose above includes all Community Edition plugins. Remove plugins you don’t need to reduce memory usage.
Web SDK Integration
Add the Countly Web SDK to your site:
<script type="text/javascript">
var Countly = Countly || {};
Countly.q = Countly.q || [];
Countly.app_key = "YOUR_APP_KEY";
Countly.url = "https://your-countly-server.example.com";
Countly.q.push(["track_sessions"]);
Countly.q.push(["track_pageview"]);
Countly.q.push(["track_errors"]);
</script>
<script async src="https://your-countly-server.example.com/sdk/web/countly.min.js"></script>
Replace YOUR_APP_KEY and the URL with your actual values from the dashboard.
Reverse Proxy
For production with SSL, put the Nginx container behind your main reverse proxy:
- Scheme: http
- Forward Hostname: countly-nginx (or host IP)
- Forward Port: 8080
See Reverse Proxy Setup for details.
Backup
MongoDB stores all analytics data. Back it up with:
docker exec countly-mongodb mongodump --archive=/bitnami/backup-$(date +%Y%m%d).gz --gzip
docker cp countly-mongodb:/bitnami/backup-$(date +%Y%m%d).gz ./
See Backup Strategy for a comprehensive backup approach.
Troubleshooting
Dashboard Loads But Shows No Data
Symptom: You can log in but no events or sessions appear.
Fix: Verify the app key in your SDK matches the key shown in Management → Applications. Check that the SDK URL points to your Countly server’s public address, not localhost. Check browser console for CORS errors.
MongoDB Connection Errors on Startup
Symptom: API and frontend containers restart repeatedly with connection errors.
Fix: MongoDB takes 30-60 seconds to initialize on first run. The depends_on with health check handles this. If it persists, check MongoDB logs: docker logs countly-mongodb.
High Memory Usage
Symptom: Server runs out of RAM after a few days.
Fix: Reduce NODE_OPTIONS max-old-space-size. Remove unused plugins from COUNTLY_PLUGINS. Consider running only essential plugins: mobile,web,plugins,views,logger,systemlogs,crashes,dashboards,sdk.
Plugins Not Loading
Symptom: Dashboard shows fewer features than expected.
Fix: Ensure the COUNTLY_PLUGINS environment variable is identical in both countly-api and countly-frontend services. Mismatched plugin lists cause features to appear broken.
Resource Requirements
- RAM: ~1.5 GB idle (MongoDB + API + Frontend + Nginx), ~3-4 GB under load
- CPU: Moderate — scales with API workers
- Disk: ~500 MB for the application, plus MongoDB growth (~1 MB per 10,000 events)
Verdict
Countly is the right choice when you need more than pageview analytics. If you’re tracking mobile app usage, custom events, crash reports, or user flows, Countly’s product analytics capabilities far exceed what Plausible or Umami offer. The trade-off is complexity — 4 containers, higher memory usage, and more configuration. For simple website analytics, Plausible or Umami are easier. For full product analytics that rivals Mixpanel or Amplitude, Countly delivers.
Frequently Asked Questions
Is the Countly Community Edition free?
Yes. The Community Edition is open source (AGPLv3) and free to self-host. It includes core analytics, crash reporting, and push notifications. The Enterprise Edition adds features like revenue analytics, A/B testing, user profiles, and funnels — those require a paid license. For most self-hosters, the Community Edition covers the essentials.
Can Countly track mobile apps?
Yes — this is Countly’s primary strength. SDKs are available for iOS, Android, React Native, Flutter, Unity, and other mobile frameworks. The mobile SDKs handle session tracking, crash reporting, custom events, and push notifications. This makes Countly more suitable for mobile app analytics than web-only tools like Plausible or Umami.
How does Countly compare to PostHog?
Both are product analytics platforms, but they target different scales. Countly focuses on mobile app analytics with crash reporting and push notifications. PostHog emphasizes feature flags, session recording, and experimentation. PostHog’s self-hosted version needs significantly more resources (8 GB+ RAM with ClickHouse). Countly runs on 1.5-4 GB RAM and is more practical for smaller teams.
Does Countly support custom events?
Yes. Track any event with custom key-value pairs through the SDK. For example, track button clicks, feature usage, purchase flows, or any user action. Custom events appear in the dashboard with counts, sums, and duration breakdowns. The Community Edition supports unlimited custom events.
How much data can Countly handle?
Countly uses MongoDB for storage, which scales well for most self-hosted scenarios. A single instance handles millions of events per month comfortably. MongoDB storage grows at roughly 1 MB per 10,000 events. For high-volume applications, configure MongoDB with WiredTiger compression and set up data retention policies to manage disk usage.
Can I send push notifications through Countly?
Yes. The Community Edition includes push notification support for iOS (APNs) and Android (FCM). Configure your Apple/Google push certificates in the Countly dashboard, then send targeted or broadcast notifications. Push notifications can be triggered manually or through automated workflows based on user segments.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments