All apps · 0 apps
AppRankly
Docker app from primer's Repository
Overview
Readme
View on GitHub
AppRankly — Mobile App Store Analytics Dashboard
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.

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

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).

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)
Clone the repository:
git clone https://github.com/zmsp/AppRankly.git cd AppRanklyCreate configuration folder & copy template:
mkdir -p data/config/keys cp example.config.json data/config/config.jsonUpdate
data/config/config.jsonwith your credentials and parameters, place your API key files (.jsonfor Google,.p8for Apple) insidedata/config/keys/, then mount thedata/directory into your container.Start the application:
docker-compose up -dAccess 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!
- Search for AppRankly in the Unraid Apps tab (or view the official listing on Unraid Community Apps).
- 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 - Navigate to Unraid Docker tab -> Add Container -> Select AppRankly template.
- Configure path permissions (
chown -R 1000:1000 /mnt/user/appdata/AppRankly/). - 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.
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.
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.
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)
- 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
.p8private key file and save it todata/config/keys/apple_key.p8.
- 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.
- Configure your Topic Name:
- Set
"ntfyTopic"indata/config/config.jsonto 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.
- Set
- Subscribe on your Device:
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 Cloud Project ID | Yes (for Google Play) | |
bucketName |
GCS Bucket name from Play Console URI | Yes (for Google Play) | |
keyFilePath |
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 |
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 |
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.
- Fork the repository (
https://github.com/zmsp/AppRankly/fork) - Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Support & My Apps
Explore more self-hosted applications at apps.shahadat.us or support ongoing development:
License
This project is open-source and licensed under the MIT License.
Media gallery
1 / 2Install 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.
Categories
Related apps
Explore more like this
Explore allDetails
ghcr.io/zmsp/apprankly:latestRuntime arguments
- Web UI
http://[IP]:[PORT:3000]- Network
bridge- Privileged
- false
Template configuration
The web interface host port mapped to container port 3000.
- Target
- 3000
- Default
- 3020
- Value
- 3020
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
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 application listening port.
- Target
- PORT
- Default
- 3000
- Value
- 3000
Internal path to the config.json configuration file.
- Target
- CONFIG_PATH
- Default
- /app/data/config/config.json
- Value
- /app/data/config/config.json
Internal directory path where app data is stored.
- Target
- DATA_DIR
- Default
- /app/data
- Value
- /app/data