https://github.com/arraypress/applytics
A lightweight, privacy-focused analytics platform for mobile apps built on Cloudflare Workers and D1
https://github.com/arraypress/applytics
Last synced: 10 months ago
JSON representation
A lightweight, privacy-focused analytics platform for mobile apps built on Cloudflare Workers and D1
- Host: GitHub
- URL: https://github.com/arraypress/applytics
- Owner: arraypress
- Created: 2025-03-09T16:05:10.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2025-03-11T16:56:35.000Z (11 months ago)
- Last Synced: 2025-03-11T17:50:04.836Z (11 months ago)
- Language: JavaScript
- Size: 14.6 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Cloudflare Applytics
A lightweight, privacy-focused analytics tracking and reporting system built on Cloudflare Workers and D1.
## Privacy-First Analytics
Cloudflare Applytics is designed to be a privacy-aware tracking solution for app developers who need minimal metrics like app installs, purchases, and user engagement without compromising user privacy.
**Privacy features:**
- No personal information tracking
- No cookies or persistent identifiers
- No cross-site tracking
- No IP address storage
- Fully compliant with privacy regulations
- Data stored in your own Cloudflare account
This solution is ideal for developers who want basic app metrics without becoming entangled in complex privacy requirements or third-party analytics that might compromise user data.
## Features
- Simple API key authentication
- Track single events or batches
- Category-based event organization
- Cumulative stats with filtering options
- Timeseries data with custom periods
- Multiple metric comparison
- Event history and detailed reporting
- Dashboard with trending metrics
## Use Cases
### App Lifecycle Events
Track critical milestones in your app's lifecycle:
```bash
# Track app installation
curl -X POST "https://your-worker.workers.dev/track" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"event_type": "install", "value": 1, "category": "lifecycle"}'
# Track app update
curl -X POST "https://your-worker.workers.dev/track" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"event_type": "update", "qualifier": "1.2.0", "category": "lifecycle"}'
# Track app uninstall
curl -X POST "https://your-worker.workers.dev/track" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"event_type": "uninstall", "category": "lifecycle"}'
```
### User Engagement
Measure how users interact with your app without tracking personal data:
```bash
# Track page views
curl -X POST "https://your-worker.workers.dev/track" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"event_type": "page_view", "qualifier": "home"}'
# Track feature usage
curl -X POST "https://your-worker.workers.dev/track" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"event_type": "feature_used", "qualifier": "dark_mode"}'
# Track button clicks
curl -X POST "https://your-worker.workers.dev/track" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"event_type": "button_click", "qualifier": "signup"}'
```
### Revenue Events
Monitor purchase and subscription events:
```bash
# Track one-time purchase
curl -X POST "https://your-worker.workers.dev/track" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"event_type": "purchase", "qualifier": "premium_upgrade", "value": 999}'
# Track subscription start
curl -X POST "https://your-worker.workers.dev/track" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"event_type": "subscription", "qualifier": "monthly_plan", "value": 499}'
# Track in-app purchase
curl -X POST "https://your-worker.workers.dev/track" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"event_type": "iap", "qualifier": "coins_pack", "value": 299}'
```
## Setup
### Prerequisites
- [Node.js](https://nodejs.org/) (version 14 or higher)
- [Cloudflare account](https://dash.cloudflare.com/sign-up)
- [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/get-started/)
### Installation
1. Clone this repository
```bash
git clone https://github.com/arraypress/cloudflare-applytics.git
cd cloudflare-applytics
```
2. Install dependencies
```bash
npm install
```
3. Update your `wrangler.toml` configuration
```toml
name = "cloudflare-applytics"
main = "src/index.js"
compatibility_date = "2023-10-02"
[vars]
ENVIRONMENT = "development"
API_KEY = "your-development-api-key"
[[d1_databases]]
binding = "DB"
database_name = "applytics_local"
database_id = "applytics-local"
```
### Database Setup
1. Create the D1 database (only needed once)
```bash
wrangler d1 create applytics_local
# Update the database_id in wrangler.toml with the ID returned
```
2. Initialize the database with schema
```bash
npm run setup
```
3. Check that tables were created successfully
```bash
npm run db
```
### Development
Start the local development server:
```bash
npm run dev
```
### Available Scripts
```bash
# Development
npm run dev # Start local development server
npm run build # Build the project
# Deployment
npm run deploy # Deploy to development environment
npm run deploy:prod # Deploy to production environment
# Database Setup & Management
npm run setup # Setup local database with schema
npm run setup:prod # Setup production database with schema
npm run db # Show database tables
npm run db:info # Show database table information
npm run db:events # Show all events
npm run db:stats # Show all stats
npm run db:reset # Reset database (deletes all data)
```
### Production Deployment
1. Update production configuration in `wrangler.toml`
2. Set API key as a secret:
```bash
wrangler secret put API_KEY --env production
```
3. Deploy to production:
```bash
npm run deploy:prod
```
## Understanding Events and Stats
### Events vs. Stats
**Events** are individual occurrences tracked in real-time:
- Each event is recorded with a timestamp
- Events have types, optional qualifiers, and values
- Events are stored in the events table
- Used for historical analysis and timeseries data
**Stats** are cumulative counters derived from events:
- Automatically updated when events are tracked
- Represent aggregate metrics (e.g., total page views)
- Stored in the stats table for efficient querying
- Used for dashboards and overall analytics
### Event Anatomy
Events consist of:
- `event_type`: The main action being tracked (e.g., "page_view", "purchase")
- `qualifier`: Optional sub-type or specific instance (e.g., "home", "premium_plan")
- `value`: Numeric value associated with the event (default: 1)
- `category`: Organizational group (e.g., "engagement", "revenue")
- `country`: Country code (automatically detected or can be provided)
- `timestamp`: When the event occurred (defaults to current time)
When an event is tracked, it creates or updates a corresponding stat with the key format `event_type.qualifier`.
### Practical Examples
**Example 1: Tracking App Usage**
Track daily active users by recording a "session" event when your app starts:
```bash
# User opens the app - track a session start
curl -X POST "https://your-worker.workers.dev/track" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"event_type": "session", "qualifier": "start"}'
# Later, analyze daily active users
curl "https://your-worker.workers.dev/timeseries?metric=session.start&period=day&limit=30" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key"
```
**Example 2: Feature Adoption**
Track how many users enable a new feature:
```bash
# User enables dark mode
curl -X POST "https://your-worker.workers.dev/track" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"event_type": "feature_enabled", "qualifier": "dark_mode"}'
# Get total count of feature enablement
curl "https://your-worker.workers.dev/stats?prefix=feature_enabled" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key"
```
**Example 3: Conversion Funnel**
Track user progression through a signup flow:
```bash
# Track each step in the signup flow
curl -X POST "https://your-worker.workers.dev/track/batch" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"events": [
{"event_type": "signup_step", "qualifier": "view_form"},
{"event_type": "signup_step", "qualifier": "submit_email"},
{"event_type": "signup_step", "qualifier": "verify_email"},
{"event_type": "signup_step", "qualifier": "complete"}
]
}'
# Compare conversion rates between steps
curl "https://your-worker.workers.dev/timeseries?metrics=signup_step.view_form,signup_step.submit_email,signup_step.verify_email,signup_step.complete&period=day" \
-H "X-App-ID: your-app-id" \
-H "X-API-Key: your-api-key"
```
## API Documentation
### Authentication
All API requests require the following headers:
- `X-App-ID`: Your application ID
- `X-API-Key`: Your API key
### Event Tracking
#### POST /track
Track a single event.
**Request Body:**
```json
{
"event_type": "page_view",
"qualifier": "home",
"value": 1,
"category": "engagement",
"timestamp": 1678912345,
"country": "US"
}
```
**Parameters:**
- `event_type` (required): Type of event
- `qualifier` (optional): Event qualifier
- `value` (optional): Numeric value, defaults to 1
- `category` (optional): Event category
- `timestamp` (optional): Unix timestamp, defaults to current time
- `country` (optional): Country code, automatically detected from request if not provided
**Response:**
```json
{
"success": true,
"app_id": "app1",
"metric": "page_view.home",
"category": "engagement",
"value": 42,
"timestamp": 1678912345,
"country": "US"
}
```
#### POST /track/batch
Track multiple events in a single request.
**Request Body:**
```json
{
"events": [
{
"event_type": "page_view",
"qualifier": "home",
"value": 1
},
{
"event_type": "button_click",
"qualifier": "signup",
"category": "interaction"
}
]
}
```
**Response:**
```json
{
"success": true,
"app_id": "app1",
"processed": 2,
"events": [
{
"event_type": "page_view",
"qualifier": "home",
"metric": "page_view.home",
"category": "engagement",
"country": "US"
},
{
"event_type": "button_click",
"qualifier": "signup",
"metric": "button_click.signup",
"category": "interaction",
"country": "US"
}
]
}
```
### Stats Endpoints
#### GET /stats
Get all stats for an application.
**Query Parameters:**
- `prefix` (optional): Filter metrics starting with prefix
- `category` (optional): Filter metrics by category
- `format` (optional): Response format, either 'simple' (default) or 'detailed'
- `view` (optional): View type, supports 'default', 'category', 'top'
- `paginate` (optional): Enable pagination (true/false)
- `page` (optional): Page number for pagination
- `pageSize` (optional): Items per page for pagination
**Response (simple format):**
```json
{
"page_view.home": 42,
"button_click.signup": 18
}
```
**Response (detailed format):**
```json
{
"app_id": "app1",
"filters": {
"prefix": null,
"category": "engagement",
"country": null
},
"data": [
{
"metric": "page_view.home",
"value": 42,
"category": "engagement",
"last_updated": "2025-03-09T12:34:56Z"
}
]
}
```
#### GET /stats?view=top
Get top metrics by value.
**Query Parameters:**
- `category` (optional): Filter by category
- `limit` (optional): Maximum number of results, defaults to 10
- `sort` (optional): Sort direction, 'asc' or 'desc' (default)
**Response:**
```json
{
"app_id": "app1",
"category": "all",
"sort": "desc",
"metrics": [
{
"metric": "page_view.home",
"value": 42,
"category": "engagement",
"last_updated": "2025-03-09T12:34:56Z"
}
]
}
```
#### GET /stats?view=category
Get stats grouped by category.
**Response:**
```json
{
"app_id": "app1",
"groupBy": "category",
"data": {
"engagement": 156,
"revenue": 2850,
"lifecycle": 42
}
}
```
### Timeseries Endpoints
#### GET /timeseries
Get time-based data for a specific metric or multiple metrics.
**Query Parameters:**
- `metric` (required if metrics not provided): Single metric name
- `metrics` (required if metric not provided): Comma-separated list of metrics to compare
- `period` (optional): Time grouping, one of 'hour', 'day', 'week', 'month', defaults to 'day'
- `limit` (optional): Maximum number of data points, defaults to 30
- `from` (optional): Start date (Unix timestamp or ISO format)
- `to` (optional): End date (Unix timestamp or ISO format)
- `country` (optional): Filter by country code
**Response for single metric:**
```json
{
"app_id": "app1",
"metric": "page_view.home",
"period": "day",
"from": "2025-02-07T00:00:00Z",
"to": "2025-03-09T00:00:00Z",
"country": null,
"data": [
{
"time_period": "2025-03-08",
"total": 15
},
{
"time_period": "2025-03-09",
"total": 27
}
]
}
```
**Response for multiple metrics:**
```json
{
"app_id": "app1",
"metrics": ["page_view.home", "page_view.settings"],
"period": "day",
"from": "2025-02-07T00:00:00Z",
"to": "2025-03-09T00:00:00Z",
"country": null,
"data": [
{
"time_period": "2025-03-08",
"page_view.home": 15,
"page_view.settings": 8
},
{
"time_period": "2025-03-09",
"page_view.home": 27,
"page_view.settings": 12
}
]
}
```
### Events Endpoints
#### GET /events
Get event history for an application.
**Query Parameters:**
- `type` (optional): Filter by event type
- `category` (optional): Filter by event category
- `country` (optional): Filter by country code
- `limit` (optional): Maximum number of events to return, defaults to 50
- `from` (optional): Start date (Unix timestamp or ISO format), defaults to 24 hours ago
**Response:**
```json
{
"app_id": "app1",
"from": "2025-03-08T12:34:56Z",
"count": 2,
"events": [
{
"id": 123,
"event_type": "page_view",
"event_category": "engagement",
"qualifier": "home",
"value": 1,
"country": "US",
"timestamp": "2025-03-09T12:34:56Z"
},
{
"id": 124,
"event_type": "button_click",
"event_category": "interaction",
"qualifier": "signup",
"value": 1,
"country": "US",
"timestamp": "2025-03-09T12:35:23Z"
}
]
}
```
### App Endpoints
#### GET /app
Get information about a specific app.
**Query Parameters:**
- `view` (optional): View type, either 'summary' (default) or 'dashboard'
**Response (summary view):**
```json
{
"app_id": "app1",
"total_events": 1542,
"first_event": "2025-01-15T08:23:45Z",
"last_event": "2025-03-09T12:34:56Z",
"metrics_count": 25,
"recent_events": [
{
"event_type": "page_view",
"qualifier": "home",
"category": "engagement",
"country": "US",
"timestamp": "2025-03-09T12:34:56Z"
}
]
}
```
#### GET /app?view=dashboard
Get dashboard data for an application.
**Response:**
```json
{
"app_id": "app1",
"summary": {
"total_events": 1542,
"first_event": "2025-01-15T08:23:45Z",
"last_event": "2025-03-09T12:34:56Z",
"metrics_count": 25
},
"recent_activity": {
"last_24h_events": 145,
"last_24h_value": 198
},
"categories": [
{
"category": "engagement",
"total": 856
},
{
"category": "revenue",
"total": 3540
}
],
"top_countries": [
{
"country": "US",
"event_count": 523,
"value_sum": 1245
},
{
"country": "GB",
"event_count": 218,
"value_sum": 532
}
]
}
```
#### GET /apps
Get a list of all available apps.
**Query Parameters:**
- `stats` (optional): Include stats summary for each app (true/false)
**Response:**
```json
{
"apps": ["app1", "app2", "app3"]
}
```
**Response with stats:**
```json
{
"apps": [
{
"app_id": "app1",
"total_events": 1542,
"first_event": "2025-01-15T08:23:45Z",
"last_event": "2025-03-09T12:34:56Z",
"metrics_count": 25
},
{
"app_id": "app2",
"total_events": 856,
"first_event": "2025-02-03T10:15:32Z",
"last_event": "2025-03-09T11:22:33Z",
"metrics_count": 18
}
]
}
```
## Client Libraries
- [ApplyticsKit](https://github.com/arraypress/ApplyticsKit) - Swift client for iOS/macOS
- More coming soon!
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.