User Statistics API Documentation#
Overview#
The User Statistics API provides comprehensive analytics about user growth, engagement, activity, and content distribution. All statistics support flexible time intervals and are optimized for dashboard visualizations.
Base URL: /api/stats
Authentication: All endpoints require API key authentication via Bearer token.
Authentication#
Include your API key in the Authorization header:
Authorization: Bearer YOUR_STATS_API_KEY
Set the API key via the STATS_API_KEY environment variable.
Base Endpoint#
GET /api/stats
All statistics are accessed through this single endpoint using the type query parameter to specify the stat type.
Query Parameters#
| Parameter | Type | Required | Description | Valid Values |
|---|---|---|---|---|
type |
string | Yes | Type of statistics to retrieve | growth, engagement, activity, breakdown |
interval |
string | No | Time interval for aggregation | day, week, month (default: day) |
limit |
number | No | Number of intervals to return | 1-365 (default: 30) |
includeTimeSeries |
boolean | No | Include time series data (engagement only) | true, false (default: false) |
Stat Types#
1. Growth Statistics#
Description: Track user sign-ups over time with cumulative totals and period-over-period growth.
Query Parameters:
type=growth(required)interval(optional, default:day)limit(optional, default: 30)
Request Example:
curl -X GET "http://localhost:3000/api/stats?type=growth&interval=day&limit=30" \
-H "Authorization: Bearer YOUR_STATS_API_KEY"
Response Schema:
{
dataPoints: Array<{
date: string; // ISO date string
totalUsers: number; // Cumulative total users up to this date
newUsers: number; // New users added in this period
}>;
currentTotal: number; // Total users as of now
periodStart: string; // ISO date string of first data point
periodEnd: string; // ISO date string of last data point
}
Example Response:
{
"dataPoints": [
{
"date": "2026-03-11T00:00:00.000Z",
"totalUsers": 100,
"newUsers": 15
},
{
"date": "2026-03-12T00:00:00.000Z",
"totalUsers": 112,
"newUsers": 12
},
{
"date": "2026-03-13T00:00:00.000Z",
"totalUsers": 125,
"newUsers": 13
}
],
"currentTotal": 125,
"periodStart": "2026-03-11T00:00:00.000Z",
"periodEnd": "2026-03-13T00:00:00.000Z"
}
2. Engagement Statistics#
Description: Track active vs inactive users with detailed content breakdown. Supports optional time series data.
Note: Only counts URL cards (excludes NOTE and HIGHLIGHT cards).
Query Parameters:
type=engagement(required)interval(optional, default:day, used ifincludeTimeSeries=true)limit(optional, default: 30, used ifincludeTimeSeries=true)includeTimeSeries(optional, default:false)
Request Example (Snapshot):
curl -X GET "http://localhost:3000/api/stats?type=engagement" \
-H "Authorization: Bearer YOUR_STATS_API_KEY"
Request Example (With Time Series):
curl -X GET "http://localhost:3000/api/stats?type=engagement&includeTimeSeries=true&interval=week&limit=12" \
-H "Authorization: Bearer YOUR_STATS_API_KEY"
Response Schema:
{
// Snapshot data (always included)
totalUsers: number; // Total registered users
activeUsers: number; // Users who created any content
inactiveUsers: number; // Users who signed in but created nothing
// Activity breakdown
usersWithCards: number; // Users who created URL cards
usersWithCollections: number; // Users who created collections
usersWithConnections: number; // Users who created connections
usersWithFollows: number; // Users who followed targets
usersWithContributions: number; // Users who added cards to others' collections
// Engagement metrics
activationRate: number; // activeUsers / totalUsers
avgActionsPerActiveUser: number; // Average actions per active user
// Optional time series data (only if includeTimeSeries=true)
dataPoints?: Array<{
date: string; // ISO date string
activeUsers: number; // Users activated in this period
newlyActivatedUsers: number; // Previously inactive users who became active
cumulativeActiveUsers: number; // Total active users up to this date
}>;
}
Example Response (Snapshot):
{
"totalUsers": 500,
"activeUsers": 320,
"inactiveUsers": 180,
"usersWithCards": 280,
"usersWithCollections": 150,
"usersWithConnections": 90,
"usersWithFollows": 200,
"usersWithContributions": 45,
"activationRate": 0.64,
"avgActionsPerActiveUser": 12.5
}
Example Response (With Time Series):
{
"totalUsers": 500,
"activeUsers": 320,
"inactiveUsers": 180,
"usersWithCards": 280,
"usersWithCollections": 150,
"usersWithConnections": 90,
"usersWithFollows": 200,
"usersWithContributions": 45,
"activationRate": 0.64,
"avgActionsPerActiveUser": 12.5,
"dataPoints": [
{
"date": "2026-03-01T00:00:00.000Z",
"activeUsers": 25,
"newlyActivatedUsers": 25,
"cumulativeActiveUsers": 275
},
{
"date": "2026-03-08T00:00:00.000Z",
"activeUsers": 30,
"newlyActivatedUsers": 30,
"cumulativeActiveUsers": 305
},
{
"date": "2026-03-15T00:00:00.000Z",
"activeUsers": 15,
"newlyActivatedUsers": 15,
"cumulativeActiveUsers": 320
}
]
}
3. Activity Statistics#
Description: Track daily content creation volume across all content types.
Note: Only counts URL cards (excludes NOTE and HIGHLIGHT cards).
Query Parameters:
type=activity(required)interval(optional, default:day)limit(optional, default: 30)
Request Example:
curl -X GET "http://localhost:3000/api/stats?type=activity&interval=day&limit=7" \
-H "Authorization: Bearer YOUR_STATS_API_KEY"
Response Schema:
{
dataPoints: Array<{
date: string; // ISO date string
cardsCreated: number; // URL cards created in this period
collectionsCreated: number; // Collections created in this period
connectionsCreated: number; // Connections created in this period
followsCreated: number; // Follows created in this period
totalActions: number; // Sum of all above
}>;
totals: {
cardsCreated: number; // Total across all periods
collectionsCreated: number; // Total across all periods
connectionsCreated: number; // Total across all periods
followsCreated: number; // Total across all periods
totalActions: number; // Sum of all totals
}
periodStart: string; // ISO date string of first data point
periodEnd: string; // ISO date string of last data point
}
Example Response:
{
"dataPoints": [
{
"date": "2026-04-08T00:00:00.000Z",
"cardsCreated": 45,
"collectionsCreated": 12,
"connectionsCreated": 8,
"followsCreated": 23,
"totalActions": 88
},
{
"date": "2026-04-09T00:00:00.000Z",
"cardsCreated": 52,
"collectionsCreated": 15,
"connectionsCreated": 10,
"followsCreated": 28,
"totalActions": 105
},
{
"date": "2026-04-10T00:00:00.000Z",
"cardsCreated": 38,
"collectionsCreated": 9,
"connectionsCreated": 6,
"followsCreated": 19,
"totalActions": 72
}
],
"totals": {
"cardsCreated": 135,
"collectionsCreated": 36,
"connectionsCreated": 24,
"followsCreated": 70,
"totalActions": 265
},
"periodStart": "2026-04-08T00:00:00.000Z",
"periodEnd": "2026-04-10T00:00:00.000Z"
}
4. Breakdown Statistics#
Description: Track content distribution by subtypes over time. Shows cumulative growth of different content categories.
Breakdowns:
- URL cards by
urlType(article, video, tool, etc.) - Collections by
accessType(OPEN, CLOSED) - Connections by
connectionType(SUPPORTS, OPPOSES, unspecified)
Note: Only counts URL cards (excludes NOTE and HIGHLIGHT cards).
Query Parameters:
type=breakdown(required)interval(optional, default:day)limit(optional, default: 30)
Request Example:
curl -X GET "http://localhost:3000/api/stats?type=breakdown&interval=week&limit=4" \
-H "Authorization: Bearer YOUR_STATS_API_KEY"
Response Schema:
{
dataPoints: Array<{
date: string; // ISO date string
urlCards: {
total: number; // Total URL cards at this date
byType: Record<string, number>; // Breakdown by urlType
};
collections: {
total: number; // Total collections at this date
byAccessType: Record<string, number>; // Breakdown by accessType
};
connections: {
total: number; // Total connections at this date
byType: Record<string, number>; // Breakdown by connectionType
};
}>;
currentTotals: {
urlCards: {
total: number; // Current total URL cards
byType: Record<string, number>; // Current breakdown by urlType
}
collections: {
total: number; // Current total collections
byAccessType: Record<string, number>; // Current breakdown by accessType
}
connections: {
total: number; // Current total connections
byType: Record<string, number>; // Current breakdown by connectionType
}
}
periodStart: string; // ISO date string of first data point
periodEnd: string; // ISO date string of last data point
}
Example Response:
{
"dataPoints": [
{
"date": "2026-03-17T00:00:00.000Z",
"urlCards": {
"total": 450,
"byType": {
"article": 180,
"video": 120,
"tool": 90,
"unspecified": 60
}
},
"collections": {
"total": 85,
"byAccessType": {
"OPEN": 60,
"CLOSED": 25
}
},
"connections": {
"total": 120,
"byType": {
"SUPPORTS": 70,
"OPPOSES": 30,
"unspecified": 20
}
}
},
{
"date": "2026-03-24T00:00:00.000Z",
"urlCards": {
"total": 520,
"byType": {
"article": 210,
"video": 140,
"tool": 105,
"unspecified": 65
}
},
"collections": {
"total": 98,
"byAccessType": {
"OPEN": 72,
"CLOSED": 26
}
},
"connections": {
"total": 145,
"byType": {
"SUPPORTS": 85,
"OPPOSES": 38,
"unspecified": 22
}
}
}
],
"currentTotals": {
"urlCards": {
"total": 520,
"byType": {
"article": 210,
"video": 140,
"tool": 105,
"unspecified": 65
}
},
"collections": {
"total": 98,
"byAccessType": {
"OPEN": 72,
"CLOSED": 26
}
},
"connections": {
"total": 145,
"byType": {
"SUPPORTS": 85,
"OPPOSES": 38,
"unspecified": 22
}
}
},
"periodStart": "2026-03-17T00:00:00.000Z",
"periodEnd": "2026-03-24T00:00:00.000Z"
}
Error Responses#
All endpoints return standard error responses:
Validation Error (400):
{
"error": "Stat type is required"
}
Authentication Error (401):
{
"error": "Unauthorized"
}
Server Error (500):
{
"error": "Failed to retrieve user stats: <error message>"
}
Implementation Notes#
Card Counting#
- Important: All card counts refer exclusively to URL cards
- NOTE cards and HIGHLIGHT cards are excluded from all statistics
- This applies to: engagement stats, activity stats, and breakdown stats
Time Intervals#
day: Data aggregated by calendar dayweek: Data aggregated by calendar week (starts Monday)month: Data aggregated by calendar month
Data Points Ordering#
- All time series data is returned in chronological order (oldest to newest)
- This makes it easy to render charts and track trends over time
Performance#
- Queries are optimized with indexes on relevant columns
- Large date ranges (limit > 100) may take longer to compute
- Breakdown stats execute three queries in parallel for better performance
Null Handling#
- Null values in
urlTypeandconnectionTypeare mapped to"unspecified" - This ensures consistent data structure in breakdown responses
Common Use Cases#
Dashboard Overview#
Get current engagement snapshot:
GET /api/stats?type=engagement
Growth Chart#
Get 90 days of user growth by week:
GET /api/stats?type=growth&interval=week&limit=13
Activity Heatmap#
Get daily activity for the past month:
GET /api/stats?type=activity&interval=day&limit=30
Content Distribution Trends#
Track content type growth over 6 months:
GET /api/stats?type=breakdown&interval=month&limit=6
Activation Funnel#
Get engagement with time series to track activation trends:
GET /api/stats?type=engagement&includeTimeSeries=true&interval=week&limit=12