ScavioScavio
ProductPricingDocs
Sign InGet Started
  1. Home
  2. Tutorials
  3. Track Which TikTok Videos Drive Your Spotify Streams
Tutorial

Track Which TikTok Videos Drive Your Spotify Streams

Use the TikTok API to find which videos using your sound actually pull reach and comments asking where to stream, so you double down on what converts.

Get Free API KeyAPI Docs

To find which TikTok videos move your Spotify streams, pull every video using your sound with Scavio's TikTok search/videos endpoint, then read each video's comments to count how many people ask where to stream the song. An API gives you TikTok-side signals (views, shares, saves, and the actual comment text), not a Spotify attribution number. So the honest answer to "why did a viral clip add only 168 streams?" is that views do not equal listening intent, and the only TikTok-measurable proxy for intent is comments asking for the song. This tutorial ranks your own posts and the user-generated clips that use your track by intent-per-view, so you stop guessing which format works and copy the one whose comments are full of "what's this song?". You will not get a clean view-to-stream ratio. What you get is a ranked list of videos and styles that correlate with people actively looking to listen.

Prerequisites

  • A Scavio API key (sk_live_...) from your dashboard; new accounts get 50 free credits. TikTok endpoints cost 1 credit each.
  • Python 3.9+ with requests, or Node.js 18+ for the JavaScript version.
  • Your TikTok username and the exact sound or hashtag name your track is published under.
  • An LLM (Claude or similar) is optional but helps classify comment intent at scale.

Walkthrough

Step 1: Resolve your username to a sec_uid

TikTok's posts endpoint needs a sec_user_id, not a handle. Hit the profile endpoint with your username first and read data.user.sec_uid out of the response. This is the two-step pattern for every per-user call in the TikTok API. Cache the sec_uid; it does not change, so you never need to repeat this lookup.

Python
import requests

HEADERS = {
    "Authorization": "Bearer sk_live_...",
    "Content-Type": "application/json",
}

resp = requests.post(
    "https://api.scavio.dev/api/v1/tiktok/profile",
    headers=HEADERS,
    json={"username": "your_artist_handle"},
)
sec_uid = resp.json()["data"]["user"]["sec_uid"]
print(sec_uid)

Step 2: Pull your own posts and their stats

Send the sec_uid to user/posts with a count to get your recent videos plus per-video stats: play_count, share_count, comment_count, and digg_count (likes). Saves and shares matter more than raw views here, because a save is the closest TikTok signal to "I want to come back to this song". Sort your posts by share and comment rate, not by views, and you will already see which of your own clips behave differently.

Python
resp = requests.post(
    "https://api.scavio.dev/api/v1/tiktok/user/posts",
    headers=HEADERS,
    json={"sec_user_id": sec_uid, "count": 30},
)
posts = resp.json()["data"]["videos"]
for v in posts:
    s = v["statistics"]
    print(v["video_id"], s["play_count"], s["share_count"], s["comment_count"])

Step 3: Find every video using your sound

Most of your reach is other people's videos using your track, not your own. Query search/videos with the sound name or a branded hashtag to collect the UGC. Each result carries the same statistics block. This is where an API beats manual scrolling: you get a structured list of clips you would never find by hand, ranked candidates for which style is spreading your song.

Python
resp = requests.post(
    "https://api.scavio.dev/api/v1/tiktok/search/videos",
    headers=HEADERS,
    json={"query": "your sound name or #yourtrackhashtag", "count": 50},
)
ugc = resp.json()["data"]["videos"]
print(f"found {len(ugc)} videos using the track")

Step 4: Read comments for listening intent

This is the step that approximates conversion. For the top videos by reach, pull video/comments and count comments that ask where to stream: "what's this song", "name of the song", "add to my playlist", "on Spotify?". That ratio of intent-comments to views is the best TikTok-only proxy you have for streams. A clip with 50k views and 40 "what song?" comments is doing more for you than a 2M-view clip with none.

Python
def intent_comments(video_id):
    resp = requests.post(
        "https://api.scavio.dev/api/v1/tiktok/video/comments",
        headers=HEADERS,
        json={"video_id": video_id, "count": 50},
    )
    comments = resp.json()["data"]["comments"]
    cues = ["what song", "name of", "spotify", "playlist", "where can i"]
    hits = [c["text"] for c in comments
            if any(q in c["text"].lower() for q in cues)]
    return len(hits), hits

Step 5: Rank by intent-per-view and copy the winner

Score every video as intent_comments divided by views. Sort descending. The top of that list is your template: the hook length, the on-screen text, the part of the song used, the call to action. Be honest about the ceiling here. The API cannot tell you a single one of those people actually streamed the track. What it tells you, repeatably, is which video styles make people ask for the song, and that is the variable you can control next time you post.

Python
scored = []
for v in posts + ugc:
    vid = v["video_id"]
    views = v["statistics"]["play_count"] or 1
    n_intent, _ = intent_comments(vid)
    scored.append((vid, n_intent / views, n_intent, views))

scored.sort(key=lambda x: x[1], reverse=True)
for vid, rate, n, views in scored[:5]:
    print(f"{vid}: {n} intent / {views} views = {rate:.5f}")

Python Example

Python
import requests

API_KEY = "sk_live_..."
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}
BASE = "https://api.scavio.dev/api/v1/tiktok"

INTENT_CUES = ["what song", "name of", "spotify", "playlist", "where can i"]


def get_sec_uid(username):
    resp = requests.post(f"{BASE}/profile", headers=HEADERS,
                         json={"username": username})
    resp.raise_for_status()
    return resp.json()["data"]["user"]["sec_uid"]


def get_my_posts(sec_uid, count=30):
    resp = requests.post(f"{BASE}/user/posts", headers=HEADERS,
                         json={"sec_user_id": sec_uid, "count": count})
    resp.raise_for_status()
    return resp.json()["data"]["videos"]


def search_sound(query, count=50):
    resp = requests.post(f"{BASE}/search/videos", headers=HEADERS,
                         json={"query": query, "count": count})
    resp.raise_for_status()
    return resp.json()["data"]["videos"]


def intent_comments(video_id, count=50):
    resp = requests.post(f"{BASE}/video/comments", headers=HEADERS,
                         json={"video_id": video_id, "count": count})
    resp.raise_for_status()
    comments = resp.json()["data"]["comments"]
    hits = [c["text"] for c in comments
            if any(q in c["text"].lower() for q in INTENT_CUES)]
    return len(hits)


def rank_videos(username, sound_query):
    sec_uid = get_sec_uid(username)
    videos = get_my_posts(sec_uid) + search_sound(sound_query)

    scored = []
    for v in videos:
        vid = v["video_id"]
        views = v["statistics"]["play_count"] or 1
        n_intent = intent_comments(vid)
        scored.append({
            "video_id": vid,
            "views": views,
            "intent": n_intent,
            "intent_per_view": n_intent / views,
        })

    scored.sort(key=lambda r: r["intent_per_view"], reverse=True)
    return scored


if __name__ == "__main__":
    rows = rank_videos("your_artist_handle", "#yourtrackhashtag")
    for r in rows[:5]:
        print(f"{r['video_id']}: {r['intent']} intent / "
              f"{r['views']} views = {r['intent_per_view']:.5f}")

JavaScript Example

JavaScript
const API_KEY = "sk_live_...";
const HEADERS = {
  Authorization: `Bearer ${API_KEY}`,
  "Content-Type": "application/json",
};
const BASE = "https://api.scavio.dev/api/v1/tiktok";

const INTENT_CUES = ["what song", "name of", "spotify", "playlist", "where can i"];

async function post(path, body) {
  const resp = await fetch(`${BASE}${path}`, {
    method: "POST",
    headers: HEADERS,
    body: JSON.stringify(body),
  });
  if (!resp.ok) throw new Error(`${path} ${resp.status}`);
  return resp.json();
}

async function getSecUid(username) {
  const data = await post("/profile", { username });
  return data.data.user.sec_uid;
}

async function getMyPosts(secUid, count = 30) {
  const data = await post("/user/posts", { sec_user_id: secUid, count });
  return data.data.videos;
}

async function searchSound(query, count = 50) {
  const data = await post("/search/videos", { query, count });
  return data.data.videos;
}

async function intentComments(videoId, count = 50) {
  const data = await post("/video/comments", { video_id: videoId, count });
  const comments = data.data.comments;
  const hits = comments.filter((c) =>
    INTENT_CUES.some((q) => c.text.toLowerCase().includes(q))
  );
  return hits.length;
}

async function rankVideos(username, soundQuery) {
  const secUid = await getSecUid(username);
  const videos = [
    ...(await getMyPosts(secUid)),
    ...(await searchSound(soundQuery)),
  ];

  const scored = [];
  for (const v of videos) {
    const views = v.statistics.play_count || 1;
    const intent = await intentComments(v.video_id);
    scored.push({
      videoId: v.video_id,
      views,
      intent,
      intentPerView: intent / views,
    });
  }

  scored.sort((a, b) => b.intentPerView - a.intentPerView);
  return scored;
}

rankVideos("your_artist_handle", "#yourtrackhashtag").then((rows) => {
  for (const r of rows.slice(0, 5)) {
    console.log(
      `${r.videoId}: ${r.intent} intent / ${r.views} views = ` +
        `${r.intentPerView.toFixed(5)}`
    );
  }
});

Expected Output

JSON
7389201144556677889: 41 intent / 52310 views = 0.00078
7388110233445566778: 12 intent / 48902 views = 0.00025
7390455667788990011: 6 intent / 211487 views = 0.00003
7387009988776655443: 2 intent / 1842009 views = 0.00000
7386554433221100998: 0 intent / 73620 views = 0.00000

Related Tutorials

    Frequently Asked Questions

    Most developers complete this tutorial in 15 to 30 minutes. You will need a Scavio API key (free tier works) and a working Python or JavaScript environment.

    A Scavio API key (sk_live_...) from your dashboard; new accounts get 50 free credits. TikTok endpoints cost 1 credit each.. Python 3.9+ with requests, or Node.js 18+ for the JavaScript version.. Your TikTok username and the exact sound or hashtag name your track is published under.. An LLM (Claude or similar) is optional but helps classify comment intent at scale.. A Scavio API key gives you 50 free credits on signup.

    Yes. The free tier includes 50 credits on signup, which is more than enough to complete this tutorial and prototype a working solution.

    Scavio has a native LangChain package (langchain-scavio), an MCP server, and a plain REST API that works with any HTTP client. This tutorial uses the raw REST API, but you can adapt to your framework of choice.

    Related Resources

    Best Of

    Best TikTok UGC Campaign Tracking APIs (May 2026)

    Read more
    Best Of

    Best TikTok UGC Tracking Tools in 2026

    Read more
    Use Case

    TikTok UGC Campaign Tracking

    Read more
    Glossary

    TikTok UGC API Tracking

    Read more
    Use Case

    TikTok UGC Campaign Performance Tracking

    Read more
    Glossary

    TikTok Unofficial API

    Read more

    Start Building

    Use the TikTok API to find which videos using your sound actually pull reach and comments asking where to stream, so you double down on what converts.

    Get Free API KeyRead the Docs
    ScavioScavio

    Real-time search API for AI agents. Search every platform, not just Google.

    Product

    • Features
    • Pricing
    • Dashboard
    • Affiliates

    Developers

    • Documentation
    • API Reference
    • Quickstart
    • MCP Integration
    • Python SDK

    Alternatives

    • Tavily Alternative
    • SerpAPI Alternative
    • Firecrawl Alternative
    • Exa Alternative

    Tools

    • JSON Formatter
    • cURL to Code
    • Token Counter
    • All Tools

    © 2026 Scavio. All rights reserved.

    Featured on TAAFT
    Terms of ServicePrivacy Policy