TikTok analytics dashboard
Build a TikTok analytics dashboard from three endpoints — profile, videos, and comments — with engagement_rate included when the endpoint supports it and the required inputs are present. 3 credits per refresh.
TikTok analytics dashboard
Build the data layer for a TikTok analytics dashboard — account KPIs at the top, a per-video performance table in the middle, and the current public comment feed of the top video at the bottom. Repeated comment requests may use the 5-minute endpoint cache; cache hits cost 0 credits, and Cache-Control: no-cache requests a billed refresh.
How do you get TikTok analytics data from an API?
Three standard-tier calls cover a full dashboard refresh: GET /v1/tiktok/profile returns follower count plus pre-computed engagement_rate and estimated_reach, GET /v1/tiktok/profile/videos returns recent videos with views, likes, comments, and shares, and GET /v1/tiktok/post/comments returns the comment feed for any video URL.
The problem
TikTok's official analytics only cover accounts you own, and the Research API is gated to academics. If you're building a creator tool, an agency report, or a brand dashboard over accounts you don't own, you need public-data endpoints — and you need engagement math that's consistent enough to chart over time.
The solution
Three standard-tier endpoints (1 credit each):
GET /v1/tiktok/profile— profile stats (params:handleoruser_id) withcomputed.engagement_rateandcomputed.estimated_reachGET /v1/tiktok/profile/videos— recent videos (param:handle; optionalsort_by=latest|popular, paginate withmax_cursor)GET /v1/tiktok/post/comments— comments on a video (param:url; paginate withcursor)
Need audience demographics (age / gender split)? GET /v1/tiktok/user/audience is available at the advanced tier (5 credits).
// recipe-tiktok-dashboard.ts
// One full dashboard refresh for a TikTok account you don't own.
// Run with: SOCIALCRAWL_KEY=sc_... npx tsx recipe-tiktok-dashboard.ts
const KEY = process.env.SOCIALCRAWL_KEY;
if (!KEY) throw new Error("Set SOCIALCRAWL_KEY");
const BASE = "https://www.socialcrawl.dev/v1";
const handle = "charlidamelio";
async function get(path: string, params: Record<string, string>) {
const url = new URL(`${BASE}/${path}`);
for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
const res = await fetch(url, { headers: { "x-api-key": KEY! } });
return (await res.json()) as {
success: boolean;
data?: Record<string, any>;
error?: { message: string };
};
}
// ── Panel 1: Account KPIs ──────────────────────────────────────────────────
const profile = await get("tiktok/profile", { handle });
if (!profile.success) throw new Error(profile.error?.message);
const kpis = {
followers: profile.data!.author.followers,
engagement_rate: profile.data!.computed.engagement_rate, // optional [0, 1] canonical metric
estimated_reach: profile.data!.computed.estimated_reach,
};
console.log("account KPIs:", kpis);
// ── Panel 2: Per-video performance table ──────────────────────────────────
const videos = await get("tiktok/profile/videos", {
handle,
sort_by: "latest",
});
const rows = (videos.data?.items ?? []).map(
(item: {
post: {
url: string;
text: string | null;
created_at: string | null;
engagement: {
views: number | null;
likes: number | null;
comments: number | null;
shares: number | null;
};
};
}) => ({
caption: item.post.text?.slice(0, 40) ?? "",
views: item.post.engagement.views,
likes: item.post.engagement.likes,
comments: item.post.engagement.comments,
shares: item.post.engagement.shares,
url: item.post.url,
}),
);
console.table(rows.slice(0, 10));
// ── Panel 3: Comment feed of the current top video ─────────────────────────
const top = [...rows].sort((a, b) => (b.views ?? 0) - (a.views ?? 0))[0];
if (top) {
const comments = await get("tiktok/post/comments", { url: top.url });
for (const c of (comments.data?.items ?? []).slice(0, 5)) {
console.log(`💬 ${c.comment?.text ?? c.text}`);
}
}Schedule this against a list of handles and write each refresh to a table keyed by (handle, date) — time-series charts of followers and engagement rate fall out for free.
What you get back
// Panel 1 — profile with computed fields:
{
"account KPIs": {
"followers": 155300000,
"engagement_rate": 0.0731, // <-- pre-computed, clamped to [0, 1]
"estimated_reach": 11352430, // <-- pre-computed
},
}
// Panel 2 — console.table of the latest videos:
// ┌─────────┬──────────────────────────┬──────────┬─────────┬──────────┬────────┐
// │ (index) │ caption │ views │ likes │ comments │ shares │
// ├─────────┼──────────────────────────┼──────────┼─────────┼──────────┼────────┤
// │ 0 │ "new dance w/ @..." │ 12400000 │ 2100000 │ 18400 │ 41000 │
// │ 1 │ "grwm for the show" │ 8100000 │ 1400000 │ 12100 │ 22000 │
// └─────────┴──────────────────────────┴──────────┴─────────┴──────────┴────────┘Credits cost
Cost per run: 3 credits per dashboard refresh (profile + videos + one comment fetch, 1 credit each). Refreshing 50 accounts daily costs 4,500 credits/month. Adding audience demographics (
/v1/tiktok/user/audience) costs 5 credits more per account.
Take it further
- See Computed fields for the exact
engagement_rateformula and[0, 1]clamping rules — and Pagination to walk past the first page of videos or comments. - Compare the account against its Instagram and YouTube with Creator engagement scoring — same
computedfields, same formula. - Track a competitor's TikTok with this exact loop, or all their platforms with Competitor tracking.
- Full endpoint list (search, hashtags, trending, transcripts, followers): TikTok API. New here? Quickstart.
Competitor tracking
Snapshot a competitor's follower counts, engagement rates, and latest posts across TikTok, Instagram, YouTube, and X in one parallel sweep — 8 credits per competitor.
Video transcription
One function that returns the spoken content of any social video — TikTok, Instagram, YouTube, Facebook, X, Reddit, or Rumble — for 10 credits per video.
