AppRankly

AppRankly

Docker app from primer's Repository

Overview

AppRankly is a self-hosted analytics dashboard and data pipeline for Apple App Store (App Store Connect API) and Google Play Store (Google Cloud Storage reports). Track app downloads, installs, uninstalls, active devices, revenue, and country breakdowns in a glassmorphic dashboard with Grafana-style custom date controls and ntfy push notifications.

AppRankly Logo

AppRankly — Mobile App Store Analytics Dashboard

License: MIT Docker Image Node.js Version Unraid Template My Apps Buy Me A Coffee PRs Welcome

A self-hosted, open-source analytics pipeline, AI-powered App Store Optimization (ASO) studio, and glassmorphic web dashboard for aggregating, visualizing, and tracking mobile app performance across the Google Play Store (via Google Cloud Storage reports) and the Apple App Store (via App Store Connect API).

Includes a single-page analytics web application, an ASO suite for keyword discovery & AI metadata audits, a headless CLI for automated cron jobs/scripting, and full Docker & Unraid container support.

Unified Analytics Dashboard

Track total installs, uninstalls, active devices, and country breakdowns across Google Play & Apple App Store in one glassmorphic interface.

Overview Dashboard

Detailed App Metrics

Drill down into individual app metrics, version performance, daily trends, and country-level user distribution tables.

App Details View

AI-Powered ASO Studio

Mine store autocomplete queries for zero-cost keyword discovery, run listing health audits, and generate AI-driven metadata optimizations (supporting OpenAI, Anthropic, and Gemini).

AI-Powered ASO Studio


Quick Start

Most users deploy this application using Docker or Unraid. Pick your preferred deployment method below.

Live Interactive Demo

Try the dashboard instantly without installing anything:
Explore the Live Interactive Demo (Running in simulated demo mode with sample data)


Option 1: Docker Compose (Recommended)

  1. Clone the repository:

    git clone https://github.com/zmsp/AppRankly.git
    cd AppRankly
    
  2. Create configuration folder & copy template:

    mkdir -p data/config/keys
    cp example.config.json data/config/config.json
    

    Update data/config/config.json with your credentials and parameters, place your API key files (.json for Google, .p8 for Apple) inside data/config/keys/, then mount the data/ directory into your container.

  3. Start the application:

    docker-compose up -d
    
  4. Access the dashboard at http://localhost:3000.


Option 2: Pre-Built Docker Image (Standalone)

Run directly using the official GitHub Container Registry image:

# 1. Pull the latest image
docker pull ghcr.io/zmsp/apprankly:latest

# 2. Create local data directory & copy example config
mkdir -p $(pwd)/data/config/keys
cp example.config.json $(pwd)/data/config/config.json

# 3. Update data/config/config.json, place keys in data/config/keys/, then launch container with mounted data volume
docker run -d \
  --name AppRankly \
  -p 3000:3000 \
  -v $(pwd)/data:/app/data \
  -e JWT_SECRET="your-secure-random-secret" \
  ghcr.io/zmsp/apprankly:latest

Option 3: Unraid Deployment

AppRankly is officially listed on Unraid Community Applications!

  1. Search for AppRankly in the Unraid Apps tab (or view the official listing on Unraid Community Apps).
  2. Alternatively, run in your Unraid terminal:
    curl -o /boot/config/plugins/dockerMan/templates-user/apprankly.xml https://raw.githubusercontent.com/zmsp/AppRankly/main/unraid/apprankly.xml
    
  3. Navigate to Unraid Docker tab -> Add Container -> Select AppRankly template.
  4. Configure path permissions (chown -R 1000:1000 /mnt/user/appdata/AppRankly/).
  5. Access the Unraid UI at http://[YOUR-SERVER-IP]:3020.

For detailed Unraid instructions, see the Unraid Guide.


Option 4: Local Node.js Development

# 1. Clone & install dependencies
git clone https://github.com/zmsp/AppRankly.git
cd AppRankly
npm install

# 2. Start development server (backend + frontend watch mode)
npm run dev

Key Features

  • Unified Cross-Platform Metrics: Aggregate installs, uninstalls, active devices, and country/device breakdowns across Google Play and Apple App Store in one unified interface.
  • AI-Powered ASO Studio: Zero-cost keyword discovery, store autocomplete fan-out mining, listing health audits, and metadata optimization powered by LLMs (OpenAI, Anthropic, Gemini).
  • Grafana-Style Date Selector: Quick relative presets (Last 7 days, 30 days, 90 days, 1 year, Custom Range) with single-day drill-downs.
  • Glassmorphic Dark Dashboard: Interactive Chart.js graphs, platform filters, country distribution tables, and app version metrics.
  • Privacy & Self-Hosted Security: Keep your App Store credentials, Google Play Cloud Storage keys, and metric data 100% on your own server. JWT authentication protected.
  • Headless CLI Utility: Command-line tool to pull metrics, backfill databases, or integrate into custom notification bots/cron jobs.
  • Lightweight & Container Ready: Multi-stage Alpine Docker image optimized for minimal footprint and low resource usage.

Authentication & Credentials Setup

To fetch live metrics from Google Play Console and Apple App Store Connect, follow the step-by-step setup below.

1. Google Play Console Setup (via GCS Reports)

Google Play Console exports daily CSV reports directly into a private Google Cloud Storage (GCS) bucket.

  1. Create GCP Service Account Key:

    • Go to Google Cloud IAM & Admin Console.
    • Create a service account (e.g. playstore-stats-reader).
    • Go to Keys -> Add Key -> Create New Key (JSON).
    • Save file to data/config/keys/google_key.json.
  2. Grant Access in Play Console:

    • Go to Google Play Console -> Users and Permissions.
    • Invite your service account email address.
    • Grant "View app information and download bulk reports (read-only)" permission.
    • Note: GCS bucket permissions can take up to 24 hours to sync after invite.
  3. Locate your GCS Bucket Name:

    • In Google Play Console, go to Download reports -> Statistics.
    • Click Copy Cloud Storage URI (e.g., gs://pubsite_prod_12345678/stats/installs/).
    • Your bucket name is the string between gs:// and the first slash: pubsite_prod_12345678.

2. Apple App Store Connect Setup (via API)

  1. Generate Sales & Reports API Key:
    • Log into App Store Connect -> Users and Access -> Integrations (Keys).
    • Click Generate API Key with Sales and Reports access role.
    • Download the .p8 private key file and save it to data/config/keys/apple_key.p8.
  2. Note Identifiers:
    • Copy your Issuer ID (UUID at the top of the Keys page).
    • Copy your Key ID (10-character code next to your key).

3. Push Notifications Setup (via ntfy.sh)

AppRankly can automatically send real-time push notification alerts whenever new daily stats or updated install numbers are fetched from Google Play or Apple App Store.

  1. Configure your Topic Name:
    • Set "ntfyTopic" in data/config/config.json to a unique topic string (e.g. "my_secret_apprankly_topic").
    • Disabling Alerts: If you leave "ntfyTopic": "" empty (or omit it), push notifications are completely OFF and no alerts will be sent.
  2. Subscribe on your Device:
    • Install the free ntfy app on iOS or Android (or open ntfy.sh in your browser).
    • Subscribe to your configured topic string to start receiving daily install & uninstall alert notifications.

Configuration Reference

Copy example.config.json to data/config/config.json, update your project parameters & credentials, and mount the data/ volume into your container (-v $(pwd)/data:/app/data):

cp example.config.json data/config/config.json

Below is the single-level config.json template example (see also example.config.json in the root directory):

{
  "name": "Production Apps",
  "projectID": "your-gcp-project-id",
  "bucketName": "pubsite_prod_12345678",
  "keyFilePath": "keys/google_key.json",
  "appleIssuerId": "xxxx-xxxx-xxxx-xxxx",
  "appleKeyId": "XXXXXXXXXX",
  "appleVendorId": "85000000",
  "keyFilePath_apple": "keys/apple_key.p8",
  "PlaystoreConsoleUrl": "https://play.google.com/console/u/0/developers/123456(changeme)",
  "ntfyTopic": "",
  "refreshIntervalHours": 1,
  "statsCheckRangeDays": 30,
  "activeStartHour": 9,
  "activeEndHour": 20,
  "appMetadata": {
    "com.example.app": {
      "consoleAppId": "123456...(changeme)"
    }
  },
  "ignoredPackages": [
    "com.example.testapp"
  ],
  "ai": {
    "defaultProvider": "openai",
    "providers": {
      "openai": {
        "apiKey": "your-openai-api-key",
        "model": "gpt-4.1-nano"
      },
      "anthropic": {
        "apiKey": "your-anthropic-api-key",
        "model": "claude-3-5-sonnet-20241022"
      },
      "gemini": {
        "apiKey": "your-gemini-api-key",
        "model": "gemini-3.6-flash"
      }
    }
  }
}

Configuration Fields

Field Platform Description Required
name Both Display label for this configuration account Yes
projectID Google Google Cloud Project ID Yes (for Google Play)
bucketName Google GCS Bucket name from Play Console URI Yes (for Google Play)
keyFilePath Google Path to service account JSON key relative to config.json Yes (for Google Play)
appleIssuerId Apple App Store Connect Issuer ID Yes (for Apple App Store)
appleKeyId Apple App Store Connect Key ID Yes (for Apple App Store)
appleVendorId Apple 8-digit Apple Vendor ID (found in App Store Connect -> Reports) Optional
keyFilePath_apple Apple Path to .p8 key file relative to config.json Yes (for Apple App Store)
PlaystoreConsoleUrl Google Base URL to your Google Play Console developer account for direct deep-linking Optional
ntfyTopic Notifications ntfy.sh topic string for push notifications. Leave empty ("") to turn alerts off Optional
refreshIntervalHours Scheduler Auto-sync frequency in hours (default: 1) Optional
statsCheckRangeDays Scheduler Lookback window in days for metric aggregations (default: 30) Optional
activeStartHour Scheduler Push notification window start hour 0-23 in local time (default: 9 AM) Optional
activeEndHour Scheduler Push notification window end hour 0-23 in local time (default: 20 / 8 PM) Optional
appMetadata Google Map of package names to metadata objects (e.g. consoleAppId for direct links) Optional
ignoredPackages Both Array of package names or bundle IDs to exclude from dashboard Optional
ai AI / ASO AI service provider configurations for automated ASO suggestions & analysis Optional

Environment Variables

Variable Default Description
PORT 3000 HTTP port for the web dashboard server
JWT_SECRET change-me... Secret key used for admin authentication tokens
CONFIG_PATH /app/data/config/config.json Path to global JSON configuration file
DATA_DIR /app/data Path to persistent app storage (database cache & system state)
NTFY_TOPIC "" Fallback ntfy push notification topic name

Headless CLI Utility

Query app statistics, trigger data syncs, or run headless reporting directly from your terminal:

# Query metrics for the first configured project (index 0)
node app/cli.js -s 0

# Query metrics by project name
node app/cli.js -s "Production Apps"

# Custom query with explicit parameters
node app/cli.js \
  --key="data/config/keys/google_key.json" \
  --projectID="your-gcp-project-id" \
  --bucketName="pubsite_prod_12345678" \
  --packageName="com.example.app"

CLI Command Options

Argument Short Description
--project -s Name or zero-based index of project in config.json
--config -c Path to config.json file (default: ../config/config.json)
--key -k Path to Google Service Account JSON key
--projectID -g Google Cloud Project ID
--bucketName -b Google Play Console GCS Bucket name
--packageName -p Specific app package identifier

Architecture & Tech Stack

Tech Stack

  • Backend: Node.js (v20+), Express.js, JWT Authentication, Fast-CSV, Google Cloud Storage SDK, JWT/ES256 Apple Signer.
  • Frontend: HTML5, Vanilla JavaScript, Chart.js visualization library, CSS3 (Glassmorphism design system).
  • Containerization: Multi-stage Docker Alpine build, Unraid XML Docker Template.

System Architecture Diagram

graph TD
    subgraph Frontend Layer
        WebUI[Glassmorphic Web Dashboard]
        StaticConfig[Static Demo Config]
    end

    subgraph Server Layer
        Express[Express API Server]
        CLI[Headless CLI Utility]
    end

    subgraph Integration Core
        GCSLib[Google Play GCS Reader]
        AppleLib[App Store Connect API Reader]
    end

    subgraph Data Sources
        GCS[(Google Cloud Storage)]
        AppStoreAPI[(App Store Connect API)]
    end

    User([User / Browser]) <--> WebUI
    WebUI <--> Express
    WebUI -- Static Mode --> StaticConfig
    Express --> GCSLib
    Express --> AppleLib
    CLI --> GCSLib
    CLI --> AppleLib
    
    GCSLib <--> GCS
    AppleLib <--> AppStoreAPI
    
    Express <--> LocalCache[(Local Cache & SQLite State)]

Troubleshooting & FAQ

1. Why does Google Play show 0 stats or permission denied errors? Google Play GCS bucket permissions can take up to 24 hours to propagate after you invite the service account email in Google Play Console. Double check that the service account has "View app information and download bulk reports (read-only)" permission.
2. How do permissions work when deploying on Unraid / Docker? The Docker container runs as non-root UID 1000 (`node`). Ensure your host data folder permissions are owned by user 1000: chown -R 1000:1000 /path/to/data
3. Can I run without live credentials for evaluation? Yes! Toggle the **Demo Mode** switch in the web UI sidebar to explore the full dashboard with realistic simulated app data.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request or open an issue for feature requests and bug reports.

  1. Fork the repository (https://github.com/zmsp/AppRankly/fork)
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Support & My Apps

Explore more self-hosted applications at apps.shahadat.us or support ongoing development:

My Apps Buy Me A Coffee


License

This project is open-source and licensed under the MIT License.

Media gallery

1 / 2

Install AppRankly on Unraid in a few clicks.

Find AppRankly in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.

Open the Apps tab on your Unraid server Search Community Apps for AppRankly Review the template variables and paths Click Install

Related apps

Details

Repository
ghcr.io/zmsp/apprankly:latest
Last Updated2026-07-24
First Seen2026-07-24

Runtime arguments

Web UI
http://[IP]:[PORT:3000]
Network
bridge
Privileged
false

Template configuration

Web UI PortPorttcp

The web interface host port mapped to container port 3000.

Target
3000
Default
3020
Value
3020
Appdata DirectoryPathrw

Main host path for persistent files (config.json, API keys, and cached stats). Ensure ownership is set to 1000:1000 (chown -R 1000:1000 /mnt/user/appdata/AppRankly).

Target
/app/data
Default
/mnt/user/appdata/AppRankly
Value
/mnt/user/appdata/AppRankly
JWT SecretVariable

Secret key used for signing JWT authentication tokens. Set to a secure random string.

Target
JWT_SECRET
Default
change-me-to-something-random
Value
change-me-to-something-random
Internal App PortVariable

Internal application listening port.

Target
PORT
Default
3000
Value
3000
Config File PathVariable

Internal path to the config.json configuration file.

Target
CONFIG_PATH
Default
/app/data/config/config.json
Value
/app/data/config/config.json
Data DirectoryVariable

Internal directory path where app data is stored.

Target
DATA_DIR
Default
/app/data
Value
/app/data