Insights
Daily likes earned by one account
/data-api/v2/insights/tiktok/{handle}/activity- Scope
- insights:read
- Freshness
- catalog read
- Group
- Insights
- Platforms
- 1 of 7
What this endpoint answers
The daily history of this account's lifetime likes received, differenced into what it earned each day. The audience count says how many people follow; this says what the account actually got while that number sat still, which is the half that prices a sponsorship.
This is a catalog read: it is served from the CRM Solid database in milliseconds, costs one budget unit, and reports how old the reading is in meta.cache_age_s. It needs the insights:read scope (Insights): Engagement rates, top posts, viral patterns, cohort benchmarks.
Good to know
- hearts_eod is exact and follower counts on this platform were not until recently. TikTok follower counts above one million were rounded to the nearest hundred thousand until 2026-08-24 and have been exact at every size since 2026-08-25, so a follower delta straddling that date carries the correction as well as real movement. Likes carry no such break.
- The count is the account's lifetime total across every video still published, so a day's change is likes arriving on the whole back catalogue. Deleting videos can push it down.
- History is thinnest here of the four platforms: 2,809 accounts had 30 or more observed days on 2026-08-30, and 2,804 of those are in the top 5,000 by followers. Read window.days_observed before trusting a per-day figure.
- change is measured against the previous OBSERVED day, and days_covered says how many calendar days that step spans. A crawl gap therefore never disappears into a single day's number: use per_day, or days_covered, rather than reading change as a daily rate.
- A day with no value is left out rather than carried forward. A missing day is a day nobody looked, not a day nothing happened.
- window.days_observed is the real denominator and it varies a lot by account. Read it before trusting a per-day figure: history begins 2026-06-09 and the deepest account in any of these catalogs held 80 days on 2026-08-30.
- audience.precision says whether the follower or subscriber number on this platform can be trusted digit for digit. GET /insights/activity/platforms carries the full explanation for each.
- Only accounts already in the catalog have a series. An account nobody has asked us about has never been rolled up.
Parameters
Every value the call accepts, with the example the spec ships so the request runs as written.
| Name | In | Required | Example | What it does |
|---|---|---|---|---|
handle | path | required | khaby.lame | TikTok handle, without the @. |
days | query | optional | 30 | Calendar days of history to read back from today, 1 to 90. The rollup begins 2026-06-09, so no account can answer for more than that. |
Call it
Authenticate with a bearer token or the x-api-key header. Keys are server-to-server credentials. Never embed one in front-end code - call the API from your own backend and forward the result.
curl "https://crmsolid.com/data-api/v2/insights/tiktok/khaby.lame/activity" \
-H "Authorization: Bearer psk_live_..."
const res = await fetch("https://crmsolid.com/data-api/v2/insights/tiktok/khaby.lame/activity", {
headers: {
Authorization: `Bearer ${process.env.CRM_SOLID_DATA_API_KEY}`,
},
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${error.code}: ${error.message} (${error.request_id})`);
}
const { data, meta } = await res.json();
import os
import requests
res = requests.get(
"https://crmsolid.com/data-api/v2/insights/tiktok/khaby.lame/activity",
headers={"Authorization": f"Bearer {os.environ['CRM_SOLID_DATA_API_KEY']}"},
timeout=30,
)
res.raise_for_status()
payload = res.json()
data, meta = payload["data"], payload["meta"]
Keys look like psk_live_... for production keys, psk_test_... for test keys and are minted in the panel.
What comes back
Success is { data, meta }. Failure is { error: { code, message, request_id } }. The body below is the spec's own example: the values in it are illustrative readings, not live numbers.
- Platform
- youtube
- Id
- UCX6OQ3DkcsbYNE6H8uQQuVA
- Handle
- mrbeast
- Name
- MrBeast
- Audience metric
- subscribers
- Audience latest
- 515,000,000
- Audience precision
- rounded
- Metric key
- views
- Metric label
- Lifetime channel views
- Metric kind
- cumulative_total
- Metric measures
- Views added across the channel's whole back catalogue on that day, not views on new uploads alone.
- Metric precision
- exact
- Window requested days
- 30
- Window from
- 2026-08-01
- Window to
- 2026-08-30
- Window days observed
- 30
- Window days spanned
- 30
- Window coverage pct
- 100
- Window longest gap days
- 0
- Summary first day
- 2026-08-01
- Summary first value
- 135,311,004,112
- Summary latest day
- 2026-08-30
- Summary latest value
- 138,536,017,550
- Summary change
- 3,225,013,438
- Summary change pct
- 2.38
- Summary per day
- 111,207,360
- Summary best day day
- 2026-08-24
- Summary best day change
- 179,293,284
{
"data": {
"platform": "youtube",
"id": "UCX6OQ3DkcsbYNE6H8uQQuVA",
"handle": "mrbeast",
"name": "MrBeast",
"audience": {
"metric": "subscribers",
"latest": 515000000,
"precision": "rounded"
},
"metric": {
"key": "views",
"label": "Lifetime channel views",
"kind": "cumulative_total",
"measures": "Views added across the channel's whole back catalogue on that day, not views on new uploads alone.",
"precision": "exact"
},
"window": {
"requested_days": 30,
"from": "2026-08-01",
"to": "2026-08-30",
"days_observed": 30,
"days_spanned": 30,
"coverage_pct": 100,
"longest_gap_days": 0
},
"summary": {
"first": {
"day": "2026-08-01",
"value": 135311004112
},
"latest": {
"day": "2026-08-30",
"value": 138536017550
},
"change": 3225013438,
"change_pct": 2.38,
"per_day": 111207360,
"best_day": {
"day": "2026-08-24",
"change": 179293284,
"days_covered": 1,
"per_day": 179293284
},
"peak": null,
"trough": null,
"per_day_per_1k_audience": 215.9
},
"series": [
{
"day": "2026-08-29",
"value": 138398053404,
"change": 111478231,
"days_covered": 1,
"per_day": 111478231
},
{
"day": "2026-08-30",
"value": 138536017550,
"change": 137964146,
"days_covered": 1,
"per_day": 137964146
}
]
},
"meta": {
"request_id": "req_9f2c41a8b3d5",
"generated_at": "2026-08-23T09:14:02.317Z",
"took_ms": 42
}
}
The meta block
request_idstringrequiredUnique id for this request. Quote it in a support ticket.
generated_atstringrequiredServer time the response was produced.
took_msintegerrequiredMilliseconds spent server-side.
pagePageoptionalsourcestringoptionalWhich backend served the payload, for endpoints with more than one.
cache_age_sintegeroptionalAge of the underlying data in seconds. 0 for live reads.
When it fails
GET /insights/tiktok/{handle}/activity documents 8 failure statuses. Branch on error.code, which is stable and enumerated; message is prose and may change.
- 401Unauthorized
unauthorized | invalid_keyNo key was presented, or the key is unknown, revoked or expired.
- 402PaymentRequired
payment_required | subscription_inactiveThe key is valid but the plan behind it cannot serve the call: the included requests are spent and overage is switched off, capped or unfunded (payment_required), or the billing period lapsed and was not renewed (subscription_inactive). Retrying does not help; paying does. The X-Plan-* headers on this response say how far past the line you are.
Carries X-Plan, X-Plan-Limit, X-Plan-Overage, X-Plan-Period-End, X-Plan-Remaining.
- 403Forbidden
forbidden_scope | forbidden_ipThe key is valid but not allowed to make this call: it lacks the scope, or the request came from an address outside the key's allowlist.
- 404NotFound
not_foundThe addressed resource does not exist.
- 422InvalidRequest
invalid_requestA parameter is malformed, out of range or mutually exclusive with another. `details` names the offending fields.
- 429RateLimited
rate_limited | quota_exceededEither the burst ceiling for the current minute or the daily quota is spent. Distinguish with the code: rate_limited clears within the minute, quota_exceeded does not clear until 00:00 UTC.
Carries Retry-After, X-Quota-Limit, X-Quota-Remaining, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-Request-Id.
- 500InternalError
internal_errorSomething failed on our side. Internals are never leaked; quote the request id.
- 503Unavailable
upstream_timeout | upstream_error | not_configuredThe request could not be served right now. BRANCH ON error.code, not on the status: 'upstream_timeout' means a source was too slow (this is what a catalog query hitting its 15-second statement timeout returns, so it is reachable from any endpoint that reads the corpus, not only the live-scrape ones) and the same call is worth retrying with backoff - narrowing it with a smaller limit, a filtered scope or a less popular account makes it far less likely; 'upstream_error' means a source was unreachable, so back off further; 'not_configured' means the capability has no backing service in this deployment, and retrying will never help.
Every response carries X-Request-Id and meta.request_id. Quote it in support requests.
Coverage and limits
This endpoint covers TikTok. Rate limits come from the tier on your key.
| Tier | Requests a minute | Requests a day | Live reads a minute |
|---|---|---|---|
| free | 30 | 1,000 | 5 |
| standard | 120 | 25,000 | 20 |
| pro | 600 | 250,000 | 60 |
| unlimited | 6,000 | 10,000,000 | 600 |
This call only draws on the ordinary per-minute and per-day columns. Every response reports where you stand in X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset and the X-Plan headers.
Start calling it
A key takes a minute to mint in the panel, no card. The reference covers authentication, the envelope, scopes, rate limits and every error code in one page.
Reference path: /data-api/reference/insights-tiktok-activity