Skip to main content

Overview

The Analytics API provides comprehensive metrics for your projects and affiliate codes, including views, downloads, playtime statistics, and revenue data. All analytics data is aggregated into time slices for efficient querying.
Analytics endpoints require authentication with appropriate scopes:
  • ANALYTICS scope for views, downloads, and playtime
  • PAYOUTS_READ scope for revenue data

Fetch Analytics Data

POST /v3/analytics
Fetch analytics data with customizable time ranges, metrics, and bucketing options.

Request Body

time_range
object
required
Defines the time period and resolution for analytics data.
return_metrics
object
required
Specify which metrics to return and how to group them.

Response Format

Returns an array of time slices, where each slice contains analytics data for that time period.
time_slices
array
Array of time slices (length determined by resolution).

Examples

Basic Views and Downloads

curl -X POST "https://api.modrinth.com/v3/analytics" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "time_range": {
      "start": "2024-01-01T00:00:00Z",
      "end": "2024-01-31T23:59:59Z",
      "resolution": { "slices": 31 }
    },
    "return_metrics": {
      "project_views": {
        "bucket_by": ["project_id"]
      },
      "project_downloads": {
        "bucket_by": ["project_id"]
      }
    }
  }'

Downloads by Version

curl -X POST "https://api.modrinth.com/v3/analytics" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "time_range": {
      "start": "2024-03-01T00:00:00Z",
      "end": "2024-03-08T00:00:00Z",
      "resolution": { "slices": 7 }
    },
    "return_metrics": {
      "project_downloads": {
        "bucket_by": ["project_id", "version_id"]
      }
    }
  }'

Views by Referrer

curl -X POST "https://api.modrinth.com/v3/analytics" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "time_range": {
      "start": "2024-03-01T00:00:00Z",
      "end": "2024-03-02T00:00:00Z",
      "resolution": { "minutes": 60 }
    },
    "return_metrics": {
      "project_views": {
        "bucket_by": ["domain", "monetized"]
      }
    }
  }'

Playtime Statistics

curl -X POST "https://api.modrinth.com/v3/analytics" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "time_range": {
      "start": "2024-01-01T00:00:00Z",
      "end": "2024-02-01T00:00:00Z",
      "resolution": { "slices": 31 }
    },
    "return_metrics": {
      "project_playtime": {
        "bucket_by": ["project_id", "loader", "game_version"]
      }
    }
  }'

Revenue Data

curl -X POST "https://api.modrinth.com/v3/analytics" \
  -H "Authorization: Bearer YOUR_TOKEN_WITH_PAYOUTS_READ" \
  -H "Content-Type: application/json" \
  -d '{
    "time_range": {
      "start": "2024-01-01T00:00:00Z",
      "end": "2024-12-31T23:59:59Z",
      "resolution": { "slices": 12 }
    },
    "return_metrics": {
      "project_revenue": {
        "bucket_by": ["project_id"]
      }
    }
  }'

Example Response

[
  [
    {
      "source_project": "ABCDEFGH",
      "metric_kind": "views",
      "domain": "youtube.com",
      "views": 1523
    },
    {
      "source_project": "ABCDEFGH",
      "metric_kind": "downloads",
      "version_id": "XYZ12345",
      "downloads": 456
    }
  ],
  [
    {
      "source_project": "ABCDEFGH",
      "metric_kind": "views",
      "domain": "discord.com",
      "views": 892
    }
  ]
]

Bucketing Behavior

Bucketing allows you to group analytics data by specific dimensions:
When bucket_by is empty, all data for that metric is aggregated:
{
  "source_project": "ABCDEFGH",
  "metric_kind": "views",
  "views": 5000
}
Bucketing by one field creates separate entries:
[
  {
    "source_project": "ABCDEFGH",
    "metric_kind": "views",
    "domain": "youtube.com",
    "views": 3000
  },
  {
    "source_project": "ABCDEFGH",
    "metric_kind": "views",
    "domain": "discord.com",
    "views": 2000
  }
]
Multiple bucket fields create combinations:
[
  {
    "source_project": "ABCDEFGH",
    "metric_kind": "views",
    "domain": "youtube.com",
    "monetized": true,
    "views": 2500
  },
  {
    "source_project": "ABCDEFGH",
    "metric_kind": "views",
    "domain": "youtube.com",
    "monetized": false,
    "views": 500
  }
]

Data Sources

Clickhouse

Views, downloads, playtime, and affiliate click data is stored in Clickhouse for high-performance querying

PostgreSQL

Revenue and conversion data comes from PostgreSQL transaction records

Privacy & Anonymization

Country data is automatically anonymized when counts are below 50 to protect user privacy. Low-traffic countries are reported as “XX”.

Best Practices

Choose resolution based on your time range:
  • Hours: Use minute-based resolution
  • Days/Weeks: Use 24-96 slices
  • Months: Use 30-31 slices
  • Years: Use 12 or 52 slices
Only bucket by fields you need:
  • Fewer buckets = faster queries
  • More buckets = more detailed data
  • Consider client-side aggregation for flexibility
Keep queries reasonable:
  • Maximum 1024 time slices
  • Minimum 60-minute resolution
  • Larger ranges need coarser resolution
Request multiple metrics in one call for efficiency:
{
  "return_metrics": {
    "project_views": { "bucket_by": [] },
    "project_downloads": { "bucket_by": [] },
    "project_playtime": { "bucket_by": [] }
  }
}

Permissions

Analytics data is filtered by project permissions:
  • You can only view analytics for projects where you have VIEW_ANALYTICS permission
  • This includes:
    • Projects you own
    • Projects where you’re a team member with analytics access
    • Projects in organizations where you have the appropriate role
Revenue data requires the PAYOUTS_READ scope in addition to ANALYTICS. Requests without this scope will return an authentication error when accessing revenue metrics.