Build a TikTok Music Trend Monitor with the Music API

Published on May 29, 2026

Why TikTok Is the World's Number One Music Discovery Engine

TikTok has rewritten how songs break. A 15-second hook can move a track from total obscurity to the Billboard Hot 100 inside a fortnight, and the platform itself reports that the majority of users discover new music there before any streaming service. For labels, A&R teams, marketing agencies, and indie artists, the question is no longer whether TikTok matters - it is whether you can spot the next breakout before your competitors do.

Manually scrolling the For You page does not scale. You need a programmatic feed of which sounds are accelerating, which creators are driving them, and which tracks are crossing from one niche into another. That is exactly what a TikTok Music Trend Monitor delivers, and in this tutorial we will build one end to end using TikLiveAPI's music endpoints. Sign up at /register/ for 100 free credits, then grab your key from /profile/ and follow along.

TikTok's Music Data Model: Sounds vs Songs

Before writing any code, the data model matters. TikTok does not think in terms of "songs" the way Spotify does. It thinks in terms of sounds. A sound has a unique music_id and can be one of three things:

  • Licensed commercial track - a song from a label catalog, often associated with an artist name in the author field.
  • Original audio - a sound created by a TikTok user, flagged via "original": true in the music object.
  • Remix or mashup - a derivative sound that can hit harder than the source track.

Every video on TikTok carries a music_info object inside its post payload, and that object is the bridge between a creator and a track. The trend monitor we are about to build pivots on this object: pull videos, extract the music_id, hydrate metadata, count occurrences over time, and rank.

Step 1: Discover Sounds via /music-posts/

The /music-posts/ endpoint takes a music_id and returns every public video that uses that sound. This is your raw signal. Pagination uses cursor and the response carries hasMore (camelCase). Authenticate with the X-Api-Key header.

import requests, time

BASE = "https://api.tikliveapi.com"
HEADERS = {"X-Api-Key": "YOUR_API_KEY"}

def fetch_music_posts(music_id, max_pages=10, count=30):
    videos, cursor, pages = [], 0, 0
    while pages < max_pages:
        r = requests.get(
            f"{BASE}/music-posts/",
            headers=HEADERS,
            params={"music_id": music_id, "count": count, "cursor": cursor},
            timeout=15,
        )
        r.raise_for_status()
        data = r.json()
        videos.extend(data.get("videos", []))
        if not data.get("hasMore"):
            break
        cursor = data.get("cursor", 0)
        pages += 1
        time.sleep(0.3)
    return videos

Each video item includes create_time (Unix seconds), play_count, digg_count, and the author block - everything you need for velocity math in Step 3.

Step 2: Resolve Sound Metadata via /music-info/

A music_id on its own tells you nothing readable. Hydrate it with /music-info/, which returns a flat object containing title, author, album, duration, original, play (a direct mp3 URL), cover, and video_count - the platform-wide use counter.

def music_info(music_id):
    r = requests.get(
        f"{BASE}/music-info/",
        headers=HEADERS,
        params={"music_id": music_id},
        timeout=15,
    )
    r.raise_for_status()
    return r.json()

info = music_info("7012345678901234567")
print(info["title"], "-", info["author"], "| total uses:", info["video_count"])

The video_count field is your global denominator. A sound with 5 million uses growing 10% is mature; a sound with 8,000 uses growing 400% is your catch-them-early target.

Step 3: Compute Velocity Per Sound

Velocity is the single most important metric in trend monitoring. Define it as posts in the last 24 hours divided by the average daily volume of the prior 7 days. A ratio above 2.0 means the sound is accelerating; above 3.0 means it is breaking out.

from datetime import datetime, timedelta

def velocity(videos):
    now = datetime.utcnow().timestamp()
    last_24h = now - 86400
    last_7d  = now - 7 * 86400

    posts_24h = sum(1 for v in videos if v["create_time"] >= last_24h)
    posts_7d  = sum(1 for v in videos if last_7d <= v["create_time"] < last_24h)

    daily_avg = posts_7d / 7 if posts_7d else 0.001
    growth = posts_24h / daily_avg
    return {
        "posts_last_24h": posts_24h,
        "posts_last_7d": posts_7d,
        "growth_rate": round(growth, 2),
    }

Run this for every music_id in your watchlist on a daily cron. Store the snapshot in Postgres or SQLite so you can chart trajectories over time.

Step 4: Find Rising Songs via /search-video/

You cannot monitor what you do not know exists. To seed your watchlist with brand-new tracks, sweep /search-video/ with music-related keywords and the publish_time=1 filter (last 24 hours), then extract every unique music_id seen in the results.

def discover_new_sounds(keywords, region=None):
    seen = {}
    for kw in keywords:
        params = {
            "keyword": kw,
            "count": 30,
            "publish_time": 1,   # 1 = last 24h
            "sort_by": 2,        # 2 = newest
        }
        if region:
            params["region"] = region
        r = requests.get(f"{BASE}/search-video/", headers=HEADERS, params=params, timeout=15)
        for v in r.json().get("videos", []):
            m = v.get("music_info") or v.get("music") or {}
            mid = m.get("id")
            if mid and mid not in seen:
                seen[mid] = {
                    "title": m.get("title"),
                    "author": m.get("author"),
                    "first_seen_keyword": kw,
                }
    return seen

candidates = discover_new_sounds(
    ["new music", "song of the summer", "indie pop", "afrobeats"],
    region="US",
)

Combine this with /user-posts/ sweeps on a curated list of tastemaker accounts (music critics, niche curators, label scouts) to widen the discovery funnel without paying for noise.

Step 5: Track Top Creators Using Each Sound

Volume alone is not signal. Ten thousand posts from accounts with 200 followers each mean nothing; a hundred posts from accounts averaging 500k followers is a tidal wave. Rank creators per sound by reach and surface the top 10.

def top_creators(videos, top_n=10):
    by_author = {}
    for v in videos:
        a = v.get("author", {})
        uid = a.get("unique_id") or a.get("id")
        if not uid:
            continue
        bucket = by_author.setdefault(uid, {
            "unique_id": uid,
            "nickname": a.get("nickname"),
            "videos": 0,
            "total_plays": 0,
        })
        bucket["videos"] += 1
        bucket["total_plays"] += int(v.get("play_count", 0))
    ranked = sorted(by_author.values(), key=lambda x: x["total_plays"], reverse=True)
    return ranked[:top_n]

If you want richer creator profiles for your A&R database, pipe each unique_id into /userinfo-by-username/ to pull camelCase counters - followerCount, heartCount, videoCount - and store them alongside the velocity snapshot.

Step 6: Build a Daily Leaderboard Table

Now stitch Steps 1 to 5 into a single daily job that writes a leaderboard row per tracked sound. The schema below is the bare minimum that gives an A&R analyst something to act on at 9 a.m.

import csv

def build_leaderboard(music_ids, out_path="leaderboard.csv"):
    rows = []
    for mid in music_ids:
        info = music_info(mid)
        vids = fetch_music_posts(mid, max_pages=20)
        vel = velocity(vids)
        rows.append({
            "sound_id": mid,
            "title": info.get("title"),
            "artist": info.get("author"),
            "is_original": info.get("original"),
            "total_uses": info.get("video_count"),
            **vel,
        })
    rows.sort(key=lambda r: r["growth_rate"], reverse=True)
    with open(out_path, "w", newline="") as f:
        w = csv.DictWriter(f, fieldnames=rows[0].keys())
        w.writeheader()
        w.writerows(rows)
    return rows

Pipe the CSV into Looker, Metabase, or a Slack digest. The first thing an analyst should see each morning is the top 20 sounds by growth_rate, filtered to total_uses < 100000.

Step 7: Detect Crossover Artists

The most valuable trend signal is geographic or niche crossover - a sound that was 90% Brazilian last week is suddenly 40% American this week. To detect it, repeat Step 1 but bucket each video's author by inferred region (using the region field on /post-detail/ or by sampling the top creator profiles) and watch the distribution shift.

from collections import Counter

def region_mix(videos):
    regions = Counter()
    for v in videos:
        r = v.get("region") or (v.get("author") or {}).get("region")
        if r:
            regions[r] += 1
    total = sum(regions.values()) or 1
    return {r: round(c / total, 3) for r, c in regions.most_common(10)}

Snapshot region_mix daily. When a region's share grows by more than 15 percentage points week over week, fire a "crossover alert" - that is your sync licensing or paid-media opportunity.

Step 8: The Catch-Them-Early Pipeline

Now we wire the full early-detection rule: flag any sound with growth_rate >= 3.0 and total_uses < 100,000. These are the tracks that are accelerating fast but have not yet saturated, which is exactly the window where label deals are won and indie marketing budgets are best spent.

def catch_them_early(leaderboard, growth_threshold=3.0, max_uses=100_000):
    alerts = []
    for row in leaderboard:
        if (row["growth_rate"] >= growth_threshold
                and (row["total_uses"] or 0) < max_uses
                and row["posts_last_24h"] >= 50):
            alerts.append(row)
    return alerts

alerts = catch_them_early(rows)
for a in alerts:
    print(f"[BREAKOUT] {a['title']} by {a['artist']} - "
          f"24h: {a['posts_last_24h']}, growth: {a['growth_rate']}x, uses: {a['total_uses']}")

Push the alert list into a Slack channel via webhook, or drop it into a Notion database where the A&R team can claim and triage each candidate. The minimum-50-posts floor filters out tiny sounds that look explosive only because they started at zero.

How Labels Use This in Production

  • Sync licensing leads - rising sounds flagged early give sync teams a 2-3 week lead on competing licensors. The play field from /music-info/ is a direct mp3 URL for instant A&R review.
  • A&R signals - independent artists trending without label backing are prime signing targets. Cross-reference the artist name from /music-info/ with public catalog data to spot the unsigned.
  • Marketing budget allocation - shift TikTok creator-marketing spend toward sounds in the catch-them-early bucket rather than already-saturated trends where CPM is inflated.
  • Catalog reactivation - when a 5-year-old track suddenly re-enters the leaderboard, marketing can ride the wave with playlist pushes, lyric videos, and remix commissions.

Limitations You Should Plan For

No monitor is omniscient. TikLiveAPI returns public, real-time data, but private songs (those a creator has manually restricted) will not appear in /music-posts/ results. Region-locked tracks - common with major-label catalogs - return uneven results outside their licensed territories, so your daily sweep should explicitly iterate over the major music markets using country codes from /region-list/. Finally, original sounds with the same title are not necessarily the same audio; always dedupe on music_id, never on title strings.

For pricing - every endpoint is 1 credit, no monthly commitment, credits never expire - see /pricing/. To stress-test these calls before writing code, the /playground/ page lets you fire requests in the browser.

FAQ

How often should I refresh the leaderboard?

Daily at minimum, with a midday refresh on the top 20 candidates. Velocity changes inside a 12-hour window for the fastest-breaking sounds, so a single nightly run can miss the peak.

How many credits will this monitor consume per day?

Roughly: 1 credit per /music-info/ lookup, plus 1 credit per page of /music-posts/ (typically 5 to 20 pages per sound). Monitoring 100 sounds with 10 pages each costs around 1,100 credits per day. At the 100 free credits granted on email verification, you can prototype before topping up.

Can I get the actual mp3 of a trending sound?

Yes - /music-info/ returns the play field with a direct mp3 URL, and /download-music/ takes a video URL and returns the underlying music file. Always confirm you have the licensing rights to use the file commercially.

What is the difference between music_id and the song's ISRC?

A TikTok music_id is internal to TikTok and does not map cleanly to an ISRC. The same commercial track can have several music_id values if it was uploaded multiple times. Always track the platform-wide aggregate by joining on artist plus title with fuzzy matching.

How do I avoid hitting the rate limit while building the daily job?

The standard limit is 200 requests per minute. Sleep 300 ms between calls inside a single sound's pagination, parallelise across sounds with a worker pool capped at 3 concurrent workers, and back off exponentially on any 429 response. Contact /contact/ if you need a higher limit for production-scale monitoring.

Ready to ship? Spin up the script, point it at 10 sounds you already care about, and let it run for a week. By day 8 you will have a baseline you can defend in a Monday A&R meeting - and probably one or two breakout candidates your competitors have not noticed yet. More tutorials over at /blog/.

Build with the TikTok API

Ready to put what you read into code? Try our endpoints live or grab the full reference.

Open Playground Read Documentation