Self-hostable deep linking, attribution, and analytics platform for mobile apps.
An open-source alternative to Branch.io and AppsFlyer.
Website · Documentation · Issues
Grovs gives you full control over your mobile app's growth stack:
- Deep Linking — Short links with deferred deep linking across iOS, Android, and web
- Attribution — Track installs, opens, reinstalls, and referrals back to their source
- Revenue Tracking — In-app purchase tracking with Apple/Google webhook integration and revenue attribution
- Analytics — Real-time dashboards with daily metrics, visitor stats, and campaign performance
- Push Notifications — Send targeted messages to your users via APNs and FCM
- Multi-tenant — One instance serves multiple apps across platforms
| Layer | Technology |
|---|---|
| Framework | Ruby on Rails 8.1 / Ruby 3.3.8 |
| Database | PostgreSQL 16 |
| Cache & Queues | Redis 6 |
| Background Jobs | Sidekiq with sidekiq-scheduler |
| Authentication | Devise + Doorkeeper (OAuth2) + OmniAuth (Google, Microsoft) |
| File Storage | AWS S3 via ActiveStorage |
| Payments | Stripe (billing), App Store Server API + Google Play Developer API (IAP) |
| Push Notifications | RPush (APNs + FCM) |
| Deployment | Docker / Kamal / docker-compose |
React Dashboard ──→ Doorkeeper OAuth2 ──→ Rails API ──→ PostgreSQL
│
Mobile SDKs (iOS/Android) ──→ SDK API ───────┤
│
Apple/Google Webhooks ──→ Webhook API ───────┤
│
Sidekiq Workers ──→ Redis
The app is multi-tenant: Instance is the top-level tenant, each instance has a test and production Project. Users belong to instances via InstanceRole. Domains are attached to projects and resolve short links.
| Subdomain | Purpose | Auth |
|---|---|---|
api.* |
Dashboard API (CRUD, analytics, config) | Doorkeeper OAuth2 |
sdk.* |
Mobile SDK (events, links, purchases) | Device fingerprint |
go.* |
Short link redirects | None |
preview.* |
Link previews | None |
# 1. Clone the repo
git clone https://github.com/grovs-io/backend.git
cd backend
# 2. Copy and configure environment variables
cp .env.example .env
# Edit .env — at minimum set the encryption keys (see below)
# 3. Generate ActiveRecord encryption keys
docker compose run --rm web bin/rails db:encryption:init
# Copy the 3 keys into your .env file
# 4. Start everything
docker compose up --build
# 5. Create the database (first time only)
docker compose exec web bundle exec rails db:create db:migrate db:seedThe app will be available at http://localhost:8765. This starts PostgreSQL, Redis, the Rails web server, and 5 Sidekiq worker processes.
Prerequisites: Ruby 3.3.8, PostgreSQL 16, Redis 6+, Node.js
# Install dependencies and set up git hooks
bin/setup
# Generate encryption keys (first time)
bin/rails db:encryption:init
# Add the output to your .env
# Create and seed the database
bin/rails db:create db:migrate db:seed
# Start the Rails server
bin/rails server
# Start all Sidekiq workers (separate terminal)
./run_sidekiq.shCopy .env.example to .env and configure. Key groups:
| Group | Required | Variables |
|---|---|---|
| Encryption | Yes | ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY, _DETERMINISTIC_KEY, _KEY_DERIVATION_SALT |
| Redis | Yes | REDIS_URL |
| Server | Yes | SERVER_HOST_PROTOCOL, SERVER_HOST |
| Dashboard | Yes | REACT_HOST_PROTOCOL, REACT_HOST |
| Database | Prod only | DATABASE_URL |
| AWS S3 | For file uploads | AWS_S3_KEY_ID, AWS_S3_ACCESS_KEY, AWS_S3_REGION, AWS_S3_BUCKET |
| For emails | SENDGRID_API_KEY |
|
| Stripe | For billing | STRIPE_API_KEY, STRIPE_STANDARD_PRICE_ID, STRIPE_WEBHOOK_SECRET |
| OAuth/SSO | For SSO login | GOOGLE_CLIENT_ID/SECRET, MICROSOFT_CLIENT_ID/SECRET |
See .env.example for full documentation of every variable.
The app uses 5 Sidekiq processes with dedicated queues:
| Process | Config | Concurrency | Purpose |
|---|---|---|---|
| worker | sidekiq_worker.yml |
20 | SDK event ingestion |
| batch | sidekiq_batch.yml |
3 | Batch event processing |
| scheduler | sidekiq_scheduler.yml |
1 | Cron-based scheduled jobs |
| device_updates | sidekiq_device_updates.yml |
3 | Device metadata updates |
| maintenance | sidekiq_maintenance.yml |
5 | Backfills and housekeeping |
Start all workers at once for development:
./run_sidekiq.shThe project uses Minitest with fixtures.
# Run the full test suite
bin/rails test
# Run a specific file
bin/rails test test/models/device_test.rb
# Run a specific directory
bin/rails test test/services/Code style is enforced with RuboCop. A pre-commit hook runs automatically if you ran bin/setup.
# Run RuboCop
bundle exec rubocop
# Auto-correct safe offenses
bundle exec rubocop -aapp/
controllers/
api/v1/ # Dashboard API & SDK API endpoints
public/ # Link redirect and display controllers
models/ # ActiveRecord models
services/ # Business logic (events, devices, IAP, attribution)
jobs/ # Sidekiq background jobs
mailers/ # Transactional emails
ee/ # Enterprise features (IAP/revenue) — see license below
config/
sidekiq_*.yml # Sidekiq process configs
routes.rb # Subdomain-based routing
db/
schema.rb # Database schema (source of truth)
migrate/ # Migrations
test/ # Minitest test suite with fixtures
lib/
tasks/ # Rake tasks (metrics, backfills, debugging)
docker compose up -d --buildCopy config/deploy.yml.example to config/deploy.yml and fill in your server IPs and registry credentials.
# First-time setup
bundle exec kamal setup
# Deploy
bundle exec kamal deploy| Platform | Repository |
|---|---|
| iOS | grovs-io/grovs-ios |
| Android | grovs-io/grovs-android |
| React Native | grovs-io/grovs-react-native |
| Flutter | grovs-io/grovs-flutter |
We welcome contributions! Here's how:
- Fork the repository
- Create a feature branch (
git checkout -b my-feature) - Make your changes
- Ensure tests pass (
bin/rails test) and RuboCop is clean (bundle exec rubocop) - Commit and push to your fork
- Open a Pull Request
Please open an issue first for major changes to discuss the approach.
Grovs uses a dual license model:
- Core (MIT) — Everything outside the
ee/directory is licensed under the MIT License. You can freely use, modify, and distribute it. - Enterprise — The
ee/directory contains enterprise features (IAP/revenue tracking) under the Grovs Enterprise License. Production use of enterprise features requires a valid subscription.
See LICENSE and ee/LICENSE for full terms.