Skip to main content

Analytics

Retrieve performance metrics for your delivered accounts, including follower counts, views, engagement rates, and per-video statistics. Analytics data is sourced from platform scraping and can be refreshed on demand.

Get Account Analytics

GET /accounts/:id/analytics

Returns aggregated analytics for an account.

curl -X GET https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/analytics \
-H "X-API-Key: tok_live_xxx"

Response:

{
"data": {
"account_id": "9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c",
"followers_count": 12400,
"following_count": 340,
"total_videos_tracked": 15,
"total_views": 580000,
"total_likes": 42000,
"total_comments": 3200,
"total_shares": 8500,
"total_bookmarks": 4100,
"average_engagement_rate": 7.24,
"average_video_views": 38667,
"weekly_post_average": 2.5,
"scraped_at": "2026-02-10T09:15:00Z"
}
}

Account Analytics Fields

FieldTypeDescription
account_idstring (UUID)The account identifier.
followers_countintegerCurrent follower count.
following_countintegerNumber of accounts followed.
total_videos_trackedintegerNumber of videos being tracked.
total_viewsintegerSum of views across all tracked videos.
total_likesintegerSum of likes across all tracked videos.
total_commentsintegerSum of comments across all tracked videos.
total_sharesintegerSum of shares across all tracked videos.
total_bookmarksintegerSum of bookmarks across all tracked videos.
average_engagement_ratefloatOverall engagement rate (percentage).
average_video_viewsfloatAverage views per video.
weekly_post_averagefloatAverage posts per week.
scraped_atstringISO 8601 timestamp of the most recent data scrape.

No Analytics Available

If no analytics data exists for the account, the API returns an error (not an empty 200):

{
"error": {
"code": "ANALYTICS_NOT_FOUND",
"message": "No analytics data found for this account. Try calling the refresh endpoint first."
}
}

Hint: Call the refresh endpoint first to trigger a scrape, then retry after a few moments.


Refresh Analytics

POST /accounts/:id/analytics/refresh

Triggers a fresh scrape of the account's analytics from the platform. Refreshes are subject to a cooldown per account and a monthly quota across your organization.

curl -X POST https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/analytics/refresh \
-H "X-API-Key: tok_live_xxx"

Response:

{
"data": {
"account_id": "9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c",
"status": "scrape_queued",
"note": "Analytics scrape has been queued. Data will be available shortly."
}
}

The status field will be one of:

StatusDescription
scrape_queuedA new scrape has been queued.
refreshedData was already fresh and has been returned.

Error — cooldown active:

{
"error": {
"code": "ANALYTICS_COOLDOWN",
"message": "Analytics were refreshed recently. Please wait before refreshing again.",
"details": {
"next_refresh_at": "2026-02-12T09:15:00Z",
"hours_remaining": 12
}
}
}

Error — monthly quota exceeded:

{
"error": {
"code": "ANALYTICS_QUOTA_EXCEEDED",
"message": "Monthly analytics refresh quota reached.",
"details": {
"monthly_quota": {
"limit": 500,
"used": 500
}
}
}
}

Check Refresh Availability

GET /accounts/:id/analytics/can-refresh

Check whether an analytics refresh is currently available for this account without triggering one.

curl -X GET https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/analytics/can-refresh \
-H "X-API-Key: tok_live_xxx"

Response — available:

{
"data": {
"account_id": "9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c",
"can_refresh": true,
"next_refresh_at": null,
"hours_remaining": 0,
"monthly_quota": {
"limit": 500,
"used": 123
}
}
}

Response — cooldown active:

{
"data": {
"account_id": "9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c",
"can_refresh": false,
"next_refresh_at": "2026-02-12T09:15:00Z",
"hours_remaining": 12,
"monthly_quota": {
"limit": 500,
"used": 124
}
}
}

Can-Refresh Fields

FieldTypeDescription
account_idstring (UUID)The account identifier.
can_refreshbooleanWhether a refresh is currently allowed.
next_refresh_atstring | nullISO 8601 timestamp of when the next refresh will be available. null if available now.
hours_remainingnumberHours until the next refresh is available. 0 if available now.
monthly_quota.limitintegerTotal monthly refresh quota.
monthly_quota.usedintegerRefreshes used this month.

Get Single Video Analytics

GET /videos/:id/analytics

Returns analytics for a single video by its analytics record ID. This is a convenience endpoint — the data comes from the same scrape triggered via POST /accounts/:id/analytics/refresh.

Note: The :id here is the id field from the video analytics records (returned by GET /accounts/:id/analytics/videos), not a platform video ID.

curl -X GET https://app.tokportal.com/api/ext/videos/va_001/analytics \
-H "X-API-Key: tok_live_xxx"

Response:

{
"data": {
"id": "va_001",
"video_id": "vid_abc123",
"url": "https://www.tiktok.com/@coolcreator99/video/7123456789",
"description": "Unboxing the new product line",
"thumbnail_url": "https://pub-xxx.r2.dev/thumbnails/thumb_001.jpg",
"upload_date": "2026-01-20T12:00:00Z",
"duration_seconds": 45,
"views": 145000,
"likes": 9800,
"comments": 420,
"shares": 1200,
"bookmarks": 890,
"engagement_rate": 7.87,
"platform": "tiktok",
"content_type": "video",
"scraped_at": "2026-02-10T09:15:00Z"
}
}

Error — video not found:

{
"error": {
"code": "VIDEO_ANALYTICS_NOT_FOUND",
"message": "No analytics data found for this video ID."
}
}

Tip: To get a video's analytics ID, first list all videos for the account with GET /accounts/:id/analytics/videos, then use the id field from the response.


Get Video-Level Analytics (by Account)

GET /accounts/:id/analytics/videos

Returns per-video performance metrics for all videos published on the account. Results are paginated.

Query Parameters

ParameterTypeDefaultDescription
sort_bystringupload_dateSort field: views, likes, engagement_rate, upload_date.
sort_orderstringdescasc or desc.
pageinteger1Page number.
per_pageinteger20Results per page (max: 100).
curl -X GET "https://app.tokportal.com/api/ext/accounts/9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c/analytics/videos?sort_by=views&sort_order=desc&page=1&per_page=10" \
-H "X-API-Key: tok_live_xxx"

Response:

{
"data": [
{
"id": "va_001",
"video_id": "vid_abc123",
"url": "https://www.tiktok.com/@coolcreator99/video/7123456789",
"description": "Unboxing the new product line",
"thumbnail_url": "https://pub-xxx.r2.dev/thumbnails/thumb_001.jpg",
"upload_date": "2026-01-20T12:00:00Z",
"duration_seconds": 45,
"views": 145000,
"likes": 9800,
"comments": 420,
"shares": 1200,
"bookmarks": 890,
"engagement_rate": 7.87,
"platform": "tiktok",
"content_type": "video",
"scraped_at": "2026-02-10T09:15:00Z"
},
{
"id": "va_002",
"video_id": "vid_def456",
"url": "https://www.tiktok.com/@coolcreator99/video/7234567890",
"description": "Day in my life using the product",
"thumbnail_url": "https://pub-xxx.r2.dev/thumbnails/thumb_002.jpg",
"upload_date": "2026-01-25T14:00:00Z",
"duration_seconds": 60,
"views": 89000,
"likes": 6200,
"comments": 310,
"shares": 780,
"bookmarks": 540,
"engagement_rate": 8.19,
"platform": "tiktok",
"content_type": "video",
"scraped_at": "2026-02-10T09:15:00Z"
}
],
"pagination": {
"page": 1,
"per_page": 10,
"total": 15,
"total_pages": 2
}
}

Video Analytics Fields

FieldTypeDescription
idstringUnique analytics record ID.
video_idstringThe TokPortal video ID.
urlstringDirect URL to the video on the platform.
descriptionstringVideo caption / description.
thumbnail_urlstringURL to the video thumbnail.
upload_datestringISO 8601 timestamp of when the video was uploaded / published.
duration_secondsintegerVideo duration in seconds.
viewsintegerTotal view count.
likesintegerTotal like count.
commentsintegerTotal comment count.
sharesintegerTotal share count.
bookmarksintegerTotal bookmark / save count.
engagement_ratefloatEngagement rate: (likes + comments + shares + bookmarks) / views * 100.
platformstringPlatform the video was published on.
content_typestringContent type (e.g., video, carousel).
scraped_atstringISO 8601 timestamp of when the data was last scraped.