Guides / End-to-end tutorials / Creator intelligence A–Z

Creator intelligence A–Z

Resolve any @handle or share link into stable IDs, walk a creator’s post timeline via cursor pagination, sample ASR transcripts and top comment sentiment, and account for every credit spent.

1. Pipeline architecture & credit budget

A production creator audit resolves mutable handles into sec_uid once, walks /v1/user/posts using the unified { cursor, has_more } contract, and enriches only the top engagement outliers with ASR caption tracks and comment samples.

ActionEndpointCost
ResolveGET /v1/resolve2 cr
Get profileGET /v1/user5 cr
Profile postsGET /v1/user/posts5 cr
TranscriptGET /v1/video/transcript2 cr
CommentsGET /v1/video/comments5 cr
Comment leadsGET /v1/video/comment-leads10 cr
Deterministic 43-credit budget. 1 resolve (2 cr) + 1 profile (5 cr) + 3 post pages (15 cr) + 3 ASR transcripts (6 cr) + 3 hot-comment pages (15 cr) = 43 credits per creator (~$0.0034 on Growth). Videos without captions return 404 at 0 credits.

2. Runnable end-to-end pipeline

TypeScript SDKPython SDKcURL / MCPcreator_intel
1import { NotFoundError, TikUltra } from 'tikultra'
2
3const client = new TikUltra({ apiKey: process.env.TIKULTRA_KEY, os: 'ios', appFlavour: 'tiktok', region: 'US' })
4let spent = 0
5const resolved = await client.resolve('https://www.tiktok.com/@tiktok')
6spent += resolved.creditsCost
7const { sec_uid: secUid, username } = resolved.data
8const profile = await client.user.profile({ sec_uid: secUid })
9spent += profile.creditsCost
10
11const posts: Array<Record<string, any>> = []
12for await (const page of client.paginate('GET', '/v1/user/posts', { params: { sec_uid: secUid, count: 30, sort: 'popular' }, maxPages: 3 })) {
13  spent += page.creditsCost
14  posts.push(...(page.data.items ?? []))
15}
16const top3 = posts.sort((a, b) => (b.stats?.digg_count ?? 0) - (a.stats?.digg_count ?? 0)).slice(0, 3)
17const dossier = []
18for (const post of top3) {
19  let captions: unknown[] = []
20  try {
21    const tr = await client.video.transcript({ aweme_id: post.aweme_id, lang: 'en' })
22    spent += tr.creditsCost
23    captions = tr.data.segments ?? []
24  } catch (err) {
25    if (!(err instanceof NotFoundError)) throw err // missing ASR track costs 0 credits
26  }
27  const cm = await client.video.comments({ aweme_id: post.aweme_id, count: 50, sort_strategy: 'hot' })
28  spent += cm.creditsCost
29  dossier.push({ awemeId: post.aweme_id, plays: post.stats?.play_count, captions: captions.length, topComments: (cm.data.items ?? []).slice(0, 5) })
30}
31console.log({ username, followers: profile.data.user?.follower_count, spent, remaining: profile.creditsRemaining, dossier })

3. Error recovery & rate-limit hygiene

Both SDKs automatically retry transient 429 and 5xx responses using Retry-After at zero extra credit cost. Catch NotFoundError around video.transcript (silent/music-only clips omit WebVTT tracks) and InsufficientCreditsError before starting multi-creator batch loops.