Home > Blog > How to Find Every Video Using a TikTok Sound
Music

How to Find Videos Using a Specific TikTok Sound

By PrimeApi·August 15, 2026·9 min read·Updated August 15, 2026

A TikTok sound page shows a video count and an endless scroll. Neither answers the question that actually matters: is this track still spreading, or did it peak three weeks ago and leave behind a large number that no longer means anything? This guide covers how to page the full video list attached to a sound with the music-posts endpoint, what each video record in that list contains, and how to turn those records into a defensible measure of a sound's reach instead of quoting a headline number.

Where the music ID comes from

Every call in this workflow is keyed on a numeric music ID, so the first job is getting one. There are two reliable routes.

From a sound URL

A TikTok sound page lives at a URL like https://www.tiktok.com/music/MAKING-MY-WAY-7224128604890990593. The trailing numeric segment is the music ID. The slug in front of it is a human-readable title and can change, so parse from the end rather than matching the whole path.

import re

def music_id_from_url(url: str):
    m = re.search(r"-(\d+)/?$", url.split("?")[0])
    return m.group(1) if m else None

print(music_id_from_url("https://www.tiktok.com/music/MAKING-MY-WAY-7224128604890990593"))
# 7224128604890990593

From a video that already uses the track

More often you start from a video rather than a sound. Every item structure in the catalogue carries the sound it was filmed over. Call post-detail on a post ID and read itemInfo.itemStruct.music.id; the same music.id field is present on the items returned by user-posts, challenge-posts and place-posts, so a feed you are already collecting doubles as a source of sound IDs at no extra cost. The full item structure is broken down in the video data guide.

Confirm the sound first with music-info

Before you spend credits paging, spend one on music-info. It takes a single required musicId and returns musicInfo, which holds three useful blocks. musicInfo.music carries id, title, album, authorName, duration, shoot_duration, playUrl, cover art at three sizes, and the original, isCopyrighted, is_commerce_music and is_unlimited_music flags. musicInfo.artist (with musicInfo.artists for tracks credited to more than one account) gives the account behind the sound, including uniqueId, nickname, secUid and signature. And musicInfo.stats.videoCount is TikTok's own count of videos using the track.

curl -s "https://api.primeapi.co/music-info?musicId=7224128604890990593" \
  -H "X-PrimeAPI-Key: YOUR_API_KEY"

Two of those fields change how you read everything that follows. original tells you whether this is a creator's own recording or a licensed release - an original sound with 40,000 videos behind it is a genuinely viral audio meme, while a commercial track with the same number is mostly a distribution artefact of being in the music library. And videoCount is your denominator: it is the number you will compare your sample against, and the number you should stop quoting on its own once you have finished reading this. The sound metadata itself is covered in more depth in the sound and music info guide.

Paging the video list with music-posts

The base URL is https://api.primeapi.co/ and authentication is the single header X-PrimeAPI-Key. music-posts requires musicId and accepts count and cursor as optional parameters.

curl -s "https://api.primeapi.co/music-posts?musicId=7224128604890990593&count=30&cursor=0" \
  -H "X-PrimeAPI-Key: YOUR_API_KEY"

The response envelope is worth reading closely, because it is not the one the profile feeds use. At the top level you get code, msg and processed_time, and the payload sits under data with three keys: videos (the array of records), cursor (an integer to send on the next call) and hasMore (also an integer, not a boolean). If you reuse a parser written for user-posts it will find nothing, so give this endpoint its own adapter.

Node.js (Axios)

const axios = require("axios");

const HEADERS = { "X-PrimeAPI-Key": "YOUR_API_KEY" };

async function soundPage(musicId, cursor = 0, count = 30) {
  const res = await axios.get("https://api.primeapi.co/music-posts", {
    params: { musicId, count, cursor },
    headers: HEADERS
  });
  console.log("Remaining credits:", res.headers["x-primeapi-balance"]);

  const data = res.data.data || {};
  return {
    videos: data.videos || [],
    cursor: data.cursor,
    hasMore: Boolean(data.hasMore)
  };
}

(async () => {
  let cursor = 0;
  let all = [];
  for (let i = 0; i < 5; i++) {
    const page = await soundPage("7224128604890990593", cursor);
    all = all.concat(page.videos);
    if (!page.hasMore) break;
    cursor = page.cursor;
  }
  console.log(all.length, "videos");
  console.log(all[0].aweme_id, all[0].play_count);
})();

Three practical notes on paging. Always advance with the cursor the API returned rather than incrementing an offset yourself. Stop on hasMore falling to 0, but also stop on an empty videos array, because a page that comes back empty while still claiming more will otherwise spin. And set a hard page ceiling in code - a sound with hundreds of thousands of videos will happily consume your entire credit balance one page at a time if nothing tells the loop to give up.

What a video record contains

The records in data.videos are video-centric and use snake_case names. These are the fields returned by a live call.

FieldHolds
aweme_idThe post ID. This is the key that unlocks everything else - hand it to post-detail.
video_idThe internal video asset identifier, distinct from the post ID.
regionRegion code the post is filed under, useful for splitting reach by market.
title, content_descCaption text. Both appear on the record; read whichever is populated.
durationClip length in seconds.
cover, origin_cover, ai_dynamic_coverStill thumbnail, unprocessed still, and the animated preview.
play, wmplayPlayable video addresses - the plain rendition and the watermarked variant.
size, wm_sizeFile sizes in bytes for those two renditions.
musicThe sound object attached to the clip, echoed back per video.
play_count, digg_count, comment_count, share_count, collect_count, download_countSix engagement counters. This set is what makes reach measurable.
create_timeUpload time as a Unix timestamp in seconds.
is_ad, commerce_info, commercial_video_infoPaid and commercial content markers.
anchors, anchors_extrasAnchor cards attached to the post.
mentioned_usersAccounts tagged in the post.
item_comment_settingsComment permission state for the clip.

A few more fields ride along beyond this list, so store the raw record rather than a hand-picked subset - re-paging a sound later to recover a field you discarded is the expensive mistake here. Note that download_count is a counter TikTok exposes on this endpoint and not on the item structure returned by post-detail, which is a small argument for keeping both.

Measuring reach instead of quoting a number

A sound with 80,000 videos sounds enormous. It is meaningless until you know how those videos are distributed. Three calculations, all of which run on fields you already have, do most of the work.

Concentration

Sum play_count across your sample, then compare the mean against the median. When the mean is many times the median, one or two large videos are carrying the whole track and the sound is not spreading - it is being watched. A sound where the top clip accounts for 60% of total plays is a single viral video with an audio credit attached, not an audio trend, and building a campaign on it means competing with that one video for attention.

Creation velocity

Bucket create_time by day. Because music-posts returns newest first, the timestamps on your first page tell you how fast the sound is currently being used. If page one spans four hours, the track is live. If page one spans five months, videoCount is a historical total and nothing more.

Engagement per play

Add digg_count, comment_count, share_count and collect_count per video and divide by play_count. Plays are the cheapest signal on the platform; saves and shares are the expensive ones. A sound whose videos collect a high collect_count relative to plays is one people intend to use themselves, which is the closest thing to a leading indicator you will find in this data.

import requests
from statistics import median

HEADERS = {"X-PrimeAPI-Key": "YOUR_API_KEY"}

def sound_videos(music_id, max_pages=5, count=30):
    videos, cursor = [], 0
    for _ in range(max_pages):
        r = requests.get(
            "https://api.primeapi.co/music-posts",
            params={"musicId": music_id, "count": count, "cursor": cursor},
            headers=HEADERS, timeout=20,
        )
        r.raise_for_status()
        data = r.json().get("data", {})
        batch = data.get("videos", [])
        if not batch:
            break
        videos += batch
        if not data.get("hasMore"):
            break
        cursor = data.get("cursor")
    return videos

vids = sound_videos("7224128604890990593")
plays = sorted((v.get("play_count") or 0) for v in vids)
total = max(sum(plays), 1)

engaged = sum(
    (v.get("digg_count") or 0) + (v.get("comment_count") or 0)
    + (v.get("share_count") or 0) + (v.get("collect_count") or 0)
    for v in vids
)

print("sampled videos:", len(vids))
print("total plays:", total)
print("mean / median:", round(total / len(plays)), "/", median(plays))
print("top video share:", round(plays[-1] / total * 100, 1), "%")
print("engagement per play:", round(engaged / total * 100, 2), "%")
print("newest / oldest:", max(v["create_time"] for v in vids),
      min(v["create_time"] for v in vids))

Report the sample size next to every one of these figures. You are measuring a sample of the newest videos on the sound, not the whole population, and a number quoted without its denominator is exactly the problem you set out to fix. Comparing your sampled totals against musicInfo.stats.videoCount tells you what fraction you actually read. For running this on a schedule across a watchlist of tracks, the trending sounds guide covers the sampling cadence.

Enriching the clips that matter

Once you have ranked a sound's videos by plays or by engagement per play, the top slice is usually worth a second call. Passing aweme_id to post-detail returns the full item structure: the author block with uniqueId, nickname and secUid, the creator's own authorStats totals, the challenges array of hashtags used alongside the sound, textExtra for caption entities, and both stats and statsV2 - the latter adding repostCount. That is how a sound audit becomes a creator shortlist: the accounts winning with a track are the accounts to approach about it.

Keep the enrichment set small and deliberate. Ten post-detail calls on the top ten videos cost 10 credits and answer the question. Ten thousand calls on the full tail cost 10,000 and answer the same question. If you also want the audio itself, download-music turns a post URL into a single play link, walked through in the audio download guide.

Credits, limits and errors

Every request costs 1 credit, including a page that comes back empty, and the default rate limit is 100 requests per minute. Data is fetched live with no caching, so counters reflect the moment you asked and responses average around a second. Read X-PrimeAPI-Balance on each response instead of polling a dashboard - it is the cheapest way to notice a runaway paging loop.

Four failures return a JSON message worth branching on: "Please sign up to primeapi.co" means no key header was sent, "PrimeAPI-Key is not available" means the key is wrong or the account is not activated, the per-minute message means you crossed the rate limit, and "Your balance has been exhausted..." means you are out of credits. A valid request against a sound with no reachable videos still succeeds and still costs a credit, so check data.videos before reading it. Full details are in the API documentation, and both endpoints can be run against your own key in the interactive playground before you write any code.

Putting it together

The workflow that holds up is four steps: resolve a music ID from a sound URL or from a video's music.id, spend one credit on music-info to confirm the track and capture videoCount, page music-posts with a hard ceiling and store the raw records, then enrich only the top slice with post-detail. Run it twice a week and the deltas in creation velocity will tell you far more than any single scrape did. Fifty free credits on a new account are enough to audit a sound end to end before you commit to a plan. PrimeApi is an independent service and is not affiliated with or endorsed by TikTok or ByteDance.

Frequently asked questions

Where do I find a TikTok music ID?

A sound page URL ends in a numeric segment - in https://www.tiktok.com/music/MAKING-MY-WAY-7224128604890990593 the music ID is 7224128604890990593. If you do not have the sound URL, take any video that uses the track and read itemInfo.itemStruct.music.id from a post-detail response, or the music.id field on any feed item returned by user-posts, challenge-posts or place-posts.

How do I page through all the videos using a sound?

music-posts takes a required musicId plus optional count and cursor. Start at cursor=0, read data.videos, then pass data.cursor back on the next call and stop when data.hasMore is 0. Note that hasMore is an integer here rather than a boolean, so test it as truthy rather than comparing it to true.

Why does music-posts look different from the other feed endpoints?

It returns a different envelope. Instead of itemList with camelCase fields, you get code, msg, processed_time and a data object holding videos, cursor and hasMore, and the video records use snake_case names such as play_count and create_time. Write a small adapter for it rather than reusing the parser you built for profile feeds.

Does music-posts tell me who made each video?

The records are video-centric: they carry aweme_id, the caption, the counters, the cover images and the playable addresses, plus mentioned_users. When you need the creator behind a clip, take its aweme_id and call post-detail, whose author block returns uniqueId, nickname, secUid and the avatars, alongside authorStats.

How many credits does auditing one sound cost?

One credit per request. A single music-info lookup is 1 credit and each page of music-posts is another, so sampling 300 videos at 30 per page costs about 11 credits in total. Enriching every one of those videos with post-detail would add 300 more, which is why it is worth enriching only the clips that matter. New accounts start with 50 free credits and the balance comes back in the X-PrimeAPI-Balance header.

Can I get the audio file for the sound itself?

Yes, two ways. music-info returns musicInfo.music.playUrl, a direct address for the track. Alternatively download-music takes a post URL and answers with a single play field holding a playable link to the audio behind that video, which is the cheaper option when you are working from video URLs rather than music IDs.

Start building with the PrimeApi TikTok API
50 free credits when you sign up. No card required - you only pay when you need more.

← Back to the PrimeApi Blog