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.
| Action | Endpoint | Cost |
|---|---|---|
| Resolve | GET /v1/resolve | 2 cr |
| Get profile | GET /v1/user | 5 cr |
| Profile posts | GET /v1/user/posts | 5 cr |
| Transcript | GET /v1/video/transcript | 2 cr |
| Comments | GET /v1/video/comments | 5 cr |
| Comment leads | GET /v1/video/comment-leads | 10 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.