Guides / End-to-end tutorials / Winning product & affiliate spy A–Z

Winning product & affiliate spy A–Z

Snipe breakout TikTok Shop (OEC) SKUs by tracking PDP inventory deltas to infer daily unit velocity, reverse-engineering top creator affiliate showcases, scraping video cart anchors, and monitoring LIVE bag rotations.

1. SKU stock-delta velocity & affiliate graph mapping

Public sales counters lag or round into coarse buckets, whereas mobile SDUI /v1/shop/product-page exposes exact per-SKU stock integers alongside flash-sale prices. Polling SKU stock across intervals (filtering restocks where currStock > prevStock) yields unit velocity, while /v1/shop/showcase, /v1/shop/anchors and /v1/shop/live-bag reveal every affiliate video and LIVE pin driving GMV.

ActionEndpointCost
Product pageGET /v1/shop/product-page25 cr
Creator showcaseGET /v1/shop/showcase25 cr
Shop anchorsGET /v1/shop/anchors25 cr
LIVE shopping bagGET /v1/shop/live-bag25 cr
Shop searchGET /v1/shop/search25 cr

2. Runnable OEC velocity & affiliate spy pipeline

TypeScript SDKPython SDKMCP / cURLoec_affiliate_spy
1import { TikUltra } from 'tikultra'
2
3const shop = new TikUltra({ apiKey: process.env.TIKULTRA_KEY, os: 'android', appFlavour: 'shop', region: 'US', city: 'los_angeles' })
4
5export async function spyProductAndAffiliates(productId: string, prevSkuStock: Record<string, number>, creatorHandle: string, liveRoomId: string) {
6  const [pdp, showcase, liveBag] = await Promise.all([
7    shop.shop.pdp(productId),
8    shop.shop.creatorShowcase(creatorHandle, { count: 30 }),
9    shop.shop.liveBag(liveRoomId),
10  ])
11  let estUnitsSold = 0, estGmvUsd = 0
12  for (const sku of pdp.data.skus ?? []) {
13    const prev = prevSkuStock[sku.sku_id]
14    if (prev !== undefined && sku.stock < prev) {
15      const delta = prev - sku.stock // ignore restock spikes where sku.stock > prev
16      estUnitsSold += delta
17      estGmvUsd    += delta * Number(sku.sale_price_usd ?? sku.price ?? 0)
18    }
19  }
20  const posts   = await shop.user.posts({ username: creatorHandle, count: 10 })
21  const anchors = await shop.shop.videoProducts(posts.data.items?.[0]?.aweme_id)
22  return {
23    estUnitsSold, estGmvUsd: Math.round(estGmvUsd * 100) / 100,
24    showcaseSkus: (showcase.data.items ?? []).length,
25    videoAnchors: anchors.data.anchors ?? [],
26    pinnedLiveProduct: liveBag.data.pinned_product ?? liveBag.data.items?.[0],
27  }
28}