Analytics API
Performer stats, output candles, co-stars, leaderboard and weekly market volume.
/analytics turns the catalog into numbers: output, rating and studio spread, co-stars, a
leaderboard, weekly market volume. All from release dates, javlibrary ratings and facet counts
we already hold. No view counts, no invented series.
Six keyed GET endpoints. Price starts at $0.60 per 1,000 calls; leaderboard and co-star
graph cost more as num grows.
Performer id
Four endpoints take q: stats, output candles, timeline, co-stars. q is an id from
/idols, a javdatabase slug like yua-mikami or a DMM-only dmm-1005467.
q is a document lookup, not a search. A Japanese name such as 三上悠亜 returns 404: it
matches neither names nor aliases. Search /idols first, pass the id:
curl -s -X POST https://api.javinfo.dev/idols \
-H "x-javinfo-key: $KEY" -H 'content-type: application/json' \
-d '{ "q": "yua" }'Stats — /analytics/idols/stats
The profile card in one call: output, span, rating, genre and studio spread, a 0–1 star score. For a performer header or shortlist ranking.
| Parameter | Type | Required | Notes |
|---|---|---|---|
q | string | yes | id or slug from /idols |
curl -s 'https://api.javinfo.dev/analytics/idols/stats?q=yua-mikami' \
-H "x-javinfo-key: jvi_your_key_here"Response 200 (lists trimmed):
{
"idol": {
"id": "yua-mikami",
"name": "Yua Mikami",
"nameJa": "三上悠亜",
"image": "https://pics.dmm.co.jp/mono/actjpgs/mikami_yua.jpg",
"tags": [
"Twenties",
"Big Tits"
],
"age": 33,
"heightCm": 159,
"cup": "G",
"debut": null,
"birthplace": "Aichi",
"aliases": [
"みかみゆあ"
]
},
"works": 1127,
"worksBySource": {
"fanza": 1127,
"javdatabase": 365,
"javlibrary": 457,
"javbus": 417,
"missav": 358
},
"firstRelease": "2015-06-01",
"lastRelease": "2026-11-20",
"releasesLast90": 30,
"avgRating": 8.02,
"ratedTitles": 168,
"studioCount": 8,
"topGenres": [
{
"genre": "Big Tits",
"count": 765
},
{
"genre": "Over 4 Hours",
"count": 610
},
"…"
],
"topStudios": [
{
"studio": "S1 NO.1 STYLE",
"count": 991
},
{
"studio": "ROOKIE",
"count": 48
},
"…"
],
"cadenceDays": 115,
"starPower": 0.885,
"starPower100": 88,
"asOf": "2026-11-08T07:34:17.700Z"
}works is the largest single-source count, not a sum. The same title sits in fanza,
javdatabase, javlibrary, javbus and missav, so adding them inflates it fourfold.
worksBySource exposes the overlap; counts never sum to works.
avgRating is javlibrary's 1–10 average over up to 200 rated titles; ratedTitles counts
the ratings behind it.
studioCount, topGenres and topStudios count deduplicated titles, never summed across
sources, so none exceeds works. Yua Mikami: works 1127, studioCount 8, top genre "Big
Tits" 765 titles, top studio "S1 NO.1 STYLE" 991.
cadenceDays is the longest gap in days between consecutive releases, not an average.
starPower blends volume, rating, last-90-day output, studio spread, career length and
recency on a 0–1 scale; starPower100 puts the same number on a 0–100 scale.
A miss returns 404:
curl -s 'https://api.javinfo.dev/analytics/idols/stats?q=nobody-zzzz-qq' \
-H "x-javinfo-key: jvi_your_key_here"{
"defined": false,
"code": "NOT_FOUND",
"status": 404,
"message": "idol not found"
}Cost: $0.60 per 1,000 calls. Codes: 200, 400, 401, 402, 404, 429.
Reference: idolStats.
Candles — /analytics/idols/ohlc
A candlestick series of a performer's career: cumulative release count, bucketed by day, week or month. A flat close means no release in that bucket; a rising one, new output.
Not a price, no view-count history. Release dates are all we can observe, so that is what the candles chart.
| Parameter | Type | Default | Range |
|---|---|---|---|
q | string | required | id or slug from /idols |
bucket | "day" | "week" | "month" | "week" | |
limit | integer | 500 | 10–2000 |
limit caps the candles returned; with more buckets, newest are kept, oldest dropped. A
limit under 10 or a bucket other than day, week or month is a 400.
curl -s 'https://api.javinfo.dev/analytics/idols/ohlc?q=yua-mikami&bucket=month&limit=12' \
-H "x-javinfo-key: jvi_your_key_here"Response 200. Twelve monthly candles cover the last year; older ones drop (candles and
ema trimmed):
{
"id": "yua-mikami",
"metric": "cumulative_releases",
"source": "catalogue",
"bucket": "month",
"candles": [
{
"t": "2025-12-01",
"o": 1075,
"h": 1083,
"l": 1075,
"c": 1083,
"v": 9
},
{
"t": "2026-01-01",
"o": 1084,
"h": 1091,
"l": 1084,
"c": 1091,
"v": 8
},
"…",
{
"t": "2026-11-01",
"o": 1125,
"h": 1127,
"l": 1125,
"c": 1127,
"v": 3
}
],
"changePct": 4.84,
"ema": [
1083,
1085,
"…"
],
"totalReleases": 1127,
"truncated": true,
"asOf": "2026-11-08T07:34:17.117Z"
}Candle fields:
| Field | Meaning |
|---|---|
t | Bucket start, YYYY-MM-DD. A week starts on Monday, a month on the 1st. |
o | Cumulative release count at the first release in the bucket. |
h | Highest cumulative count reached inside the bucket. |
l | Lowest cumulative count inside the bucket. |
c | Cumulative count at the last release in the bucket. |
v | Number of observations in the bucket. |
In the catalogue series one observation is one release row, so v counts releases in that
bucket. A two-release bucket opens on the count after the first, closes after the second, and
reports v: 2.
metric and source say which series you got. Once the snapshot job has at least two days
recorded, the endpoint switches to metric: "star_power" and
source: "snapshots": candles then measure star score over time, scaled by 1,000, with
totalReleases: 0 and truncated: false.
changePct is the change from first open to last close, across returned candles; ema is a
7-period exponential moving average of the closes, the same length as candles.
truncated: true means older candles were dropped to fit limit; newest always stay.
totalReleases is the full career count, whatever limit. Raise limit up to 2000 candles
for the whole curve.
Cost: $0.60 per 1,000 calls. Codes: 200, 400, 401, 402, 404, 429.
Reference: idolOhlc.
Timeline — /analytics/idols/timeline
Monthly release counts plus the four values a profile page needs: debut, latest release, peak month, longest gap. All from release dates.
| Parameter | Type | Required | Notes |
|---|---|---|---|
q | string | yes | id or slug from /idols |
curl -s 'https://api.javinfo.dev/analytics/idols/timeline?q=yua-mikami' \
-H "x-javinfo-key: jvi_your_key_here"Response 200 (months trimmed):
{
"id": "yua-mikami",
"debut": "2015-06-01",
"latest": "2026-11-24",
"peakMonth": "2023-07",
"longestGapDays": 115,
"months": [
{ "month": "2015-06", "releases": 2 },
{ "month": "2015-09", "releases": 2 }
],
"truncated": false,
"asOf": "2026-11-06T18:31:34.750Z"
}months is ascending YYYY-MM, only months with a release. peakMonth is the busiest;
longestGapDays the largest gap between consecutive release dates.
latest comes from its own newest-first query, so it stays exact when truncated is true.
That flag means the ascending page hit 10,000 rows; the monthly list then stops short of
newest releases.
Cost: $0.60 per 1,000 calls. Codes: 200, 400, 401, 402, 404, 429.
Reference: idolTimeline.
Co-stars — /analytics/idols/costars
Collaborators ranked by shared titles. One facet query over the filmography; the performer is excluded.
| Parameter | Type | Default | Range |
|---|---|---|---|
q | string | required | id or slug from /idols |
num | integer | 15 | 1–50 |
curl -s 'https://api.javinfo.dev/analytics/idols/costars?q=yua-mikami&num=3' \
-H "x-javinfo-key: jvi_your_key_here"Response 200 (results trimmed):
{
"id": "yua-mikami",
"count": 3,
"results": [
{ "name": "Aika Yumeno", "sharedTitles": 771 },
{ "name": "Miharu Usa", "sharedTitles": 675 }
],
"asOf": "2026-11-06T18:31:34.119Z"
}sharedTitles counts titles with both names in the catalog.
Cost: $0.90 per 1,000 calls at num=15. num up to 10 costs $0.60; above that the price
scales to $3.00 at num=50. Codes: 200, 400, 401, 402, 404,
429. Reference: idolCostars.
Leaderboard — /analytics/leaderboard
Ranks performers over a window by three metrics.
metric | Ranks by | score |
|---|---|---|
releases | Output in the window | The performer's releases ÷ the leader's releases, 0–1 |
rating | Adjusted javlibrary average | 0–1 |
momentum | The window against the one before | Ratio ÷ 3, capped at 1 |
| Parameter | Type | Default | Range |
|---|---|---|---|
range | integer | 90 | 7–365, a number of days |
metric | "releases" | "rating" | "momentum" | "releases" | |
num | integer | 20 | 1–100 |
curl -s 'https://api.javinfo.dev/analytics/leaderboard?range=30&metric=releases&num=3' \
-H "x-javinfo-key: jvi_your_key_here"Response 200 (results trimmed):
{
"metric": "releases",
"range": 30,
"count": 3,
"truncated": false,
"results": [
{
"name": "Yui Hatano",
"nameJa": null,
"releases": 67,
"avgRating": null,
"studios": 10,
"lastRelease": "2026-11-06",
"score": 1
},
{
"name": "Yui Tenma",
"nameJa": null,
"releases": 55,
"avgRating": null,
"studios": 4,
"lastRelease": "2026-11-06",
"score": 0.821
}
],
"asOf": "2026-11-06T18:31:35.824Z"
}releases is an exact facet count. studios and lastRelease come from the 1,000 newest
hits, so they can undercount on a long range.
avgRating is javlibrary's 1–10 average for rated titles, or null when none. rating ranks
only performers with any rated title, pulling the average toward a 3.5/5 prior by rated count;
one 10/10 cannot top the list.
momentum divides this window's release count by the previous equal-length window. No
releases before gives a ratio of 2, scoring 0.667. Ties break on release count.
name is the facet key: Latin when the index has one, Japanese otherwise. nameJa is always
null today.
truncated: true means the name facet hit the index's value cap, so counts cover top names,
not everyone.
A bad enum is 400; the failing parameter is in data.issues[].path:
curl -s 'https://api.javinfo.dev/analytics/leaderboard?metric=views' \
-H "x-javinfo-key: jvi_your_key_here"{
"defined": false,
"code": "BAD_REQUEST",
"status": 400,
"message": "Input validation failed",
"data": {
"issues": [
{
"code": "invalid_value",
"values": ["releases", "rating", "momentum"],
"path": ["metric"],
"message": "Invalid option: expected one of \"releases\"|\"rating\"|\"momentum\""
}
]
}
}The same shape covers every other analytics parameter: an out-of-range range, a num above
100, a bad bucket. The issue names the parameter.
Cost: $1.20 per 1,000 calls at num=20. num up to 10 costs $0.60; above that the price
scales to $6.00 at num=100. Codes: 200, 400, 401, 402, 429.
Reference: leaderboard.
Market — /analytics/market
Weekly release volume across the DMM + FANZA catalog, plus genres gaining and losing over the window. For a homepage chart or a "what is moving" panel.
| Parameter | Type | Default | Range |
|---|---|---|---|
weeks | integer | 12 | 2–52 |
movers | integer | 10 | 1–50 |
curl -s 'https://api.javinfo.dev/analytics/market?weeks=4&movers=3' \
-H "x-javinfo-key: jvi_your_key_here"Response 200 (trimmed):
{
"weeks": 4,
"volume": [
{ "week": "2026-10-09", "releases": 1319 },
{ "week": "2026-10-16", "releases": 1421 }
],
"totalReleases": 5740,
"changePct": 1,
"truncated": false,
"genres": {
"gainers": [
{ "genre": "Knee-High Socks", "changePct": 700, "current": 8, "previous": 1 },
{ "genre": "Widow", "changePct": 700, "current": 16, "previous": 2 }
],
"losers": [
{ "genre": "Female Soldier", "changePct": -100, "current": 0, "previous": 19 },
{ "genre": "Fisting", "changePct": -100, "current": 0, "previous": 5 }
]
},
"asOf": "2026-11-06T18:31:37.397Z"
}volume has one entry per 7-day window, oldest first; week is the start date. These roll
back from today, not calendar weeks.
weeks sets the window count; totalReleases is their sum. changePct compares newest with
oldest, one decimal.
genres compares the latest floor(weeks ÷ 2) weeks with the preceding span. Genres under 5
releases in both spans are skipped; small genres add no noise. changePct is current
against previous; none before shows 100. gainers and losers are cut to movers.
truncated: true means the genre facet hit its value cap, so lists cover top genres only.
Cost: $0.60 per 1,000 calls. weeks and movers do not change the price. Codes:
200, 400, 401, 402, 429. Reference: market.
Cost
| Endpoint | Default page | Per 1,000 calls |
|---|---|---|
/analytics/idols/stats | $0.60 | |
/analytics/idols/ohlc | limit=500 | $0.60 |
/analytics/idols/timeline | $0.60 | |
/analytics/idols/costars | num=15 | $0.90 |
/analytics/leaderboard | num=20 | $1.20 |
/analytics/market | $0.60 |
Size on other endpoints does not affect price: limit, weeks and movers are free to
raise.
Only a fresh 200 is charged; cache hits, errors and degraded answers are free. Responses
cache 30 to 60 minutes; a repeat inside is a hit. See
rate limits and billing.
Common errors
401 no key. The key gate passes it; the handler refuses:
curl -s 'https://api.javinfo.dev/analytics/leaderboard'{
"defined": false,
"code": "UNAUTHORIZED",
"status": 401,
"message": "Unauthorized"
}401 bad key. Rejected earlier by the key gate, with a shorter body:
curl -s 'https://api.javinfo.dev/analytics/leaderboard' \
-H "x-javinfo-key: jvi_not_a_real_key"{ "error": "invalid api key" }Same status, two bodies. Branch on the status code, not code.
402 not enough credit. Nothing is charged. Retry-After: 3600 is advisory; a top-up
unblocks immediately:
{
"defined": false,
"code": "PAYMENT_REQUIRED",
"status": 402,
"message": "insufficient balance"
}429 over the per-minute cap. Applied before the handler, with Retry-After in
seconds:
{ "error": "rate limit exceeded" }The cap is per account, not per key. See rate limits.