SocialCrawl

TikTok analytics dashboard

Build a TikTok analytics dashboard from three endpoints — profile, videos, and comments — with engagement_rate pre-computed on every response. 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 live comment feed of the current top video at the bottom.

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: handle or user_id) with computed.engagement_rate and computed.estimated_reach
  • GET /v1/tiktok/profile/videos — recent videos (param: handle; optional sort_by=latest|popular, paginate with max_cursor)
  • GET /v1/tiktok/post/comments — comments on a video (param: url; paginate with cursor)

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, // [0, 1], same formula on every platform
  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_rate formula 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 computed fields, 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.
How to Build a TikTok Analytics Dashboard with an API | Socialcrawl