# TikTok Sound Scraper - Videos by Song, Music ID or URL (`s-r/tiktok-sound-scraper`) Actor

Scrape every TikTok video that used a sound. Paste the music link from any video or the bare id and get the videos with captions, authors, views, likes, comments and shares, plus a row describing the track itself.

- **URL**: https://apify.com/s-r/tiktok-sound-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Business
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## TikTok Sound Scraper: every video that used a song

Paste the music link from any TikTok video, or the bare sound id, and get every
video that used that sound: caption, author, follower count, views, likes,
comments, shares, post date and the media addresses. Plus one row describing
the track itself.

No login, no API key, no TikTok developer account.

### What you get

**Per video**: `video_id`, `url`, `description`, `created_at`, `handle`,
`nickname`, `author_id`, `author_verified`, `follower_count`,
`author_video_count`, `play_count`, `like_count`, `comment_count`,
`share_count`, `collect_count`, `duration_seconds`, `width`, `height`,
`cover_url`, `play_url`, `download_url`, `hashtags`, `is_ad`, and the
`sound_id` the row belongs to.

**Per sound**: `music_id`, `music_title`, `music_author`, `music_url`,
`music_cover_url`, `music_duration_seconds`, `music_is_original`,
`music_album`, and `videos_returned`.

**Optional**: eight extra author fields, and downloads of the videos,
thumbnails, avatars, sound artwork and photo-post slideshow images into the
run's key-value store.

### Why a sound is the unit worth tracking

On TikTok a sound is a format. When a track starts moving, the accounts using
it are the accounts about to get reach, and the ones who got there first are
visible in the post dates. A record label, a brand and a creator all want the
same export from that: who used it, how big they are, how well it did for them,
and when.

The app shows you a sound page and no way to export it. This is that page as
rows.

### Where to find a sound id

Open any TikTok video and the sound is the link at the bottom. It looks like:

```
https://www.tiktok.com/music/original-sound-7286756730682476546
https://www.tiktok.com/music/Dance-Monkey-6745334339318729474
```

Paste the whole link or just the number at the end. The words in the middle are
decorative and are ignored; the number is what resolves. Anything that is
neither a sound link nor a plausible id is reported by name rather than
silently skipped, so a run of fifty tells you exactly which line was wrong.

### This one pages properly

Unlike a lot of TikTok surfaces, the sound feed is a real paginated feed:
about 30 videos per request with a working cursor, measured at **0.5 to 0.7
seconds a page**. Three pages returned 87 distinct videos.

So `maxVideosPerSound` is the honest control over both time and cost. There is
no re-asking trick and no rotation to work around.

### The track's own details come off the first video

TikTok's sound page renders nothing on the server: there is no track record on
it to read, and the endpoint that would return one answers with an error. So
the title, author, artwork, duration and whether it is an original or a
licensed track are read off the first video in the feed, where TikTok includes
them in full.

That has one consequence worth stating plainly. **A sound with no videos gets
no sound row**, because there is nothing to read it from. The run reports
`soundsWithoutVideos` so an empty answer reads as empty rather than as a
failure.

### Filters cost pages, and the summary says so

Every filter is applied to the rows the run collected. The feed takes no date
or popularity parameter, so a narrow window reads **more** pages and returns
fewer rows. The summary carries `videosScanned`, `videosRejectedByFilters` and
`pagesRead` so the cost of a filter is visible rather than hidden.

### Input

| Field | Type | Notes |
|---|---|---|
| `sounds` | array | Music links or bare ids, one per line. Required. |
| `maxVideosPerSound` | integer | Default 60, up to 400. About 30 per request. |
| `resultsPerPage` | integer | 1 to 30, default 30. |
| `sortBy` | select | `relevance`, `most_liked`, `most_viewed`, `most_commented`, `most_shared`, `newest`, `oldest`. |
| `oldestPostDate` | string | `YYYY-MM-DD`, an ISO timestamp, or `7 days` / `3 months`. |
| `newestPostDate` | string | Same formats. |
| `leastDiggs` | integer | Minimum likes. |
| `mostDiggs` | integer | Maximum likes. Useful for finding small accounts. |
| `excludeAds` | boolean | Drop rows TikTok marks as advertising. |
| `scrapeAdditionalAuthorMeta` | boolean | Eight extra author fields. Free. |
| `shouldDownloadVideos` | boolean | Store the MP4 and put a working link on the row. |
| `shouldDownloadCovers` | boolean | Store the thumbnail. |
| `shouldDownloadAvatars` | boolean | Store the author avatar. |
| `shouldDownloadMusicCovers` | boolean | Store the sound artwork. |
| `shouldDownloadSlideshowImages` | boolean | Store each image of a photo post. |
| `maxMediaDownloads` | integer | Ceiling across every download option. Default 50. |
| `country` | string | Two-letter code. Feeds are regional. |
| `language` | string | Two-letter code. |
| `proxyCountryCode` | string | Where the request should appear to come from. |

### Media links that actually work

A raw media address from TikTok returns 403 to anyone who pastes it elsewhere.
Turn on a download option and the file lands in the run's key-value store with
a public link on the row, which works anywhere.

Photo posts have no video at all. Those rows carry `slideshow_images`, and the
slideshow option stores each image.

### What people use this for

**Catching a sound early.** Sort by oldest and the first users of a track are
the top rows. Run the same sound weekly and the growth is the row count.

**Creator discovery.** Everyone using a sound, with follower counts, filtered
to accounts below a ceiling. That is a list of creators in a format, priced
before they are expensive.

**Rights and licensing.** `music_is_original` separates a creator's own audio
from a licensed track, and `music_album` names the release when there is one.

**Campaign measurement.** A branded sound run daily gives the number of videos,
the total views across them and who posted, without asking anyone to report it.

### Notes

View, like and comment counts are live and change through the day. A run is a
snapshot.

A sound with no videos, or an id that is not a sound, is reported with the
reason rather than returning an empty table that reads as a track nobody used.

Free Apify plans are capped at 10 results per run. The run stops collecting at
that point rather than paging the whole feed and discarding it.

# Actor input Schema

## `sounds` (type: `array`):

One per line. Paste the music link from a TikTok video (https://www.tiktok.com/music/original-sound-7286756730682476546) or the bare id. The slug in the link is decorative and is ignored; the number at the end is what resolves.

## `maxVideosPerSound` (type: `integer`):

The sound feed pages properly, about 30 videos per request, so this is the real ceiling on both time and cost.

## `resultsPerPage` (type: `integer`):

How many videos to ask for per request, up to 30. Lower means more requests for the same total.

## `sortBy` (type: `string`):

Applied to the rows this run collected, not to TikTok's feed order. 'Relevance' keeps TikTok's own ordering untouched.

## `oldestPostDate` (type: `string`):

YYYY-MM-DD, a full ISO timestamp, or a relative window such as '7 days' or '3 months'. Filtering happens after the fetch, so a narrow window reads more pages and returns fewer rows.

## `newestPostDate` (type: `string`):

Same formats as the field above.

## `leastDiggs` (type: `integer`):

Drop videos with fewer likes than this.

## `mostDiggs` (type: `integer`):

Drop videos with more likes than this. Useful for finding small accounts rather than the same viral posts.

## `excludeAds` (type: `boolean`):

Drop rows TikTok marks as advertising.

## `scrapeAdditionalAuthorMeta` (type: `boolean`):

Adds the author's bio, avatar, region, following count and total likes. Free: the fields are already in the response.

## `shouldDownloadVideos` (type: `boolean`):

Stores the MP4 in the run's key-value store and puts a public link on the row. TikTok's raw media links return 403 to anyone who pastes them elsewhere, which is why downloading is the only way to get a link that works.

## `shouldDownloadCovers` (type: `boolean`):

Stores each video's thumbnail in the key-value store and puts a public link on the row.

## `shouldDownloadAvatars` (type: `boolean`):

Stores the author's or account's profile picture and puts a public link on the row.

## `shouldDownloadMusicCovers` (type: `boolean`):

Stores the artwork of the sound used in the video.

## `shouldDownloadSlideshowImages` (type: `boolean`):

Photo posts have no video at all. This stores each image instead.

## `maxMediaDownloads` (type: `integer`):

A ceiling across every download option, so a large search cannot turn into a large bill by accident.

## `country` (type: `string`):

Two-letter country code sent with the request. TikTok serves follower lists regionally, so this can change the ordering.

## `language` (type: `string`):

Two-letter language code for the search.

## `proxyCountryCode` (type: `string`):

Two-letter code for where the request should appear to come from. Leave empty to use the default route. Setting the country above changes what TikTok ranks; setting this changes where the request arrives from, and the two are worth matching.

## Actor input object example

```json
{
  "sounds": [
    "https://www.tiktok.com/music/original-sound-7286756730682476546",
    "7286756730682476546"
  ],
  "maxVideosPerSound": 60,
  "resultsPerPage": 30,
  "sortBy": "relevance",
  "oldestPostDate": "2026-01-01",
  "newestPostDate": "2026-06-30",
  "excludeAds": false,
  "scrapeAdditionalAuthorMeta": false,
  "shouldDownloadVideos": false,
  "shouldDownloadCovers": false,
  "shouldDownloadAvatars": false,
  "shouldDownloadMusicCovers": false,
  "shouldDownloadSlideshowImages": false,
  "maxMediaDownloads": 50,
  "country": "us",
  "language": "en",
  "proxyCountryCode": "gb"
}
```

# Actor output Schema

## `results` (type: `string`):

One row per sound and one per video that used it.

## `summary` (type: `string`):

What was asked for, what came back and how many pages it took.

## `errors` (type: `string`):

Targets that returned nothing, with the reason.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "sounds": [
        "7286756730682476546"
    ],
    "country": "us",
    "language": "en"
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/tiktok-sound-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "sounds": ["7286756730682476546"],
    "country": "us",
    "language": "en",
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/tiktok-sound-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "sounds": [
    "7286756730682476546"
  ],
  "country": "us",
  "language": "en"
}' |
apify call s-r/tiktok-sound-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/tiktok-sound-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/frchENY9MRyQ6aRfF/builds/DYUbf1H5QvF50p393/openapi.json
