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

  1. Wait 1-2 minutes for MongoDB to initialize and Countly to start
  2. Open http://your-server-ip:8080 in your browser
  3. Complete the setup wizard:
    • Create an admin account (email and password)
    • Enter your application name
    • Select the platform (web, mobile, desktop)
  4. 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 CoresRecommended Workers
1-22
44
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 RAMRecommended Setting
4 GB1024
8 GB2048
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.

Comments