# TikTok Music Posts Scraper (`maximedupre/tiktok-music-posts-scraper`) Actor

Collect TikTok music posts linked to selected sounds, or return matching sound records without expanding them. Use sound IDs, TikTok sound page URLs, or keywords and review structured sound, post, creator, engagement, and source-link fields.

- **URL**: https://apify.com/maximedupre/tiktok-music-posts-scraper.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** Social media, Videos, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.15 / 1,000 music posts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### 🎵 Find TikTok Posts by Sound

For music researchers, social media teams, and creators, this Actor finds public TikTok sounds and the video posts that use them. It saves structured sound and post data with creators, captions, engagement counts, and source links, so you can compare how sounds are used and review the data in a dataset.

- Find videos that use a selected sound with **[TikTok music posts](https://apify.com/maximedupre/tiktok-music-posts-scraper/examples/tiktok-music-posts)**.
- Pull posts from a TikTok sound page with **[TikTok sound URL scraper](https://apify.com/maximedupre/tiktok-music-posts-scraper/examples/tiktok-sound-url-scraper)**.
- Collect posts for one or more sound IDs with **[TikTok sound ID scraper](https://apify.com/maximedupre/tiktok-music-posts-scraper/examples/tiktok-sound-id-scraper)**.
- Find matching sounds from a song name or phrase with **[TikTok song finder](https://apify.com/maximedupre/tiktok-music-posts-scraper/examples/tiktok-song-finder)**.
- Search TikTok sounds by a word or phrase with **[TikTok sound search](https://apify.com/maximedupre/tiktok-music-posts-scraper/examples/tiktok-sound-search)**.

#### 📦 TikTok sound and post rows

The default dataset contains sound rows or post rows. Sound rows keep the sound identity and metadata. Post rows keep the post details and the sound linked to that post. Source URLs remain references to TikTok pages or media, not downloaded files.

#### ▶️ Run from an ID, URL, or keyword

**Run steps**

1. Choose `Posts` to collect videos for each selected or discovered sound, or choose `Sounds` to return sound metadata only.
2. Choose one source method: `Sound IDs`, `Sound page URLs`, or `Keyword`. Fill only the matching source field because inactive source fields are ignored.
3. Add sound IDs, public TikTok sound page URLs, or one or more discovery keywords. A region preference applies only to keyword discovery.
4. Set `Sounds per keyword` or `Posts per sound` when you want a limit. Leave either field empty to return all available results until the source is exhausted.
5. Start the Actor and open the dataset link in the Output panel.

#### ⚙️ Input

**Input fields**

| Field | Type | What it does |
| --- | --- | --- |
| `resultType` | string | Choose `posts` to collect video posts linked to each selected or discovered sound, or `sounds` to return sound metadata without expanding sounds into posts. |
| `findBy` | string | Chooses one source method: `soundIds`, `soundUrls`, or `keyword`. Enter values only in the matching source field. |
| `soundIds` | array of strings | One or more TikTok sound IDs used when `findBy` is `soundIds`. |
| `soundUrls` | array of objects | One or more public TikTok music or sound page entries used when `findBy` is `soundUrls`. |
| `soundUrls[].url` | string | The public TikTok music or sound page URL for one entry. |
| `keywords` | array of strings | One or more keywords used to find matching TikTok sounds when `findBy` is `keyword`. |
| `region` | string | Optional region preference used only for keyword discovery, such as `US`. Leave it blank to use the source default. |
| `maxSoundsPerKeyword` | integer | Limits matching sounds returned or used for each discovery keyword. Leave it empty to return all available matching sounds for each keyword until the source is exhausted. |
| `maxPostsPerSound` | integer | Limits posts collected for each selected or discovered sound when `resultType` is `posts`. It is ignored for `sounds`. Leave it empty to return all available posts for each sound until the source is exhausted. |

**Example input**

This example uses the prefilled post flow with one sound ID.

```json
{
  "resultType": "posts",
  "findBy": "soundIds",
  "soundIds": [
    "6787016446238017538"
  ],
  "maxPostsPerSound": 20
}
```

#### 🧾 Output

The Output panel provides a link to the default dataset. The dataset uses two materially different row shapes.

**Run output**

| Field | Type | What it does |
| --- | --- | --- |
| `results` | string | Opens the collected sound or post rows in the default dataset. |

**Sound row fields**

| Field | Type | What it does |
| --- | --- | --- |
| `resultType` | string | Always `sound` for a sound row. |
| `discoveryKeyword` | string | The keyword that first led to the sound during keyword discovery, when applicable. |
| `sound` | object | Sound data reported by TikTok. |
| `sound.soundId` | string | TikTok's sound ID. |
| `sound.title` | string | Sound title. This is required for a sound row. |
| `sound.artist` | string | Artist reported for the sound, when available. |
| `sound.album` | string | Album reported for the sound, when available. |
| `sound.durationSeconds` | number | Sound duration in seconds, when available. |
| `sound.artworkUrl` | string | Link to the sound artwork, when available. |
| `sound.audioUrl` | string | TikTok audio reference, when available. This is not a file download. |
| `sound.sourcePageUrl` | string | TikTok page for the sound, when available. |
| `sound.postCount` | integer | Number of posts reported for the sound, when available. |
| `sound.rights` | object | Rights details reported by TikTok, when available. |
| `sound.rights.isOriginal` | boolean | Whether TikTok reports the sound as original. |
| `sound.rights.isCommercial` | boolean | Whether TikTok reports the sound as commercial. |
| `sound.rights.isCopyrighted` | boolean | Whether TikTok reports the sound as copyrighted. |

**Example sound row**

This unshortened row is a genuine sound row from a successful keyword search.

```json
{
  "resultType": "sound",
  "discoveryKeyword": "music",
  "sound": {
    "soundId": "7467649576808303377",
    "title": "original sound",
    "artist": "8D MUSIC 🎧",
    "durationSeconds": 66,
    "artworkUrl": "https://p16-common-sign.tiktokcdn-eu.com/tos-alisg-avt-0068/eded1d7d312cd3ae000c4270a098f0ea~tplv-tiktokx-cropcenter:1080:1080.jpeg?dr=10399&refresh_token=dc69921e&x-expires=1790161200&x-signature=fqxjgl9BpKpPA16ohwMEG7kOMAY%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=81f88b70&idc=no1a",
    "audioUrl": "https://v45.tiktokcdn-eu.com/24d3e9898976a0e07b27e1cedfa0770a/6ab26915/video/tos/alisg/tos-alisg-v-27dcd7/oY5VEzBz0ugiKVozABMAQ5XfdlYwZiIBQ2oAoT/?a=1233&bti=ODszNWYuMDE6&&bt=125&ft=cD1VS7z7ThWH5W7HLGZmo0P&mime_type=audio_mpeg&rc=ZThlO2VoPGU5Ojo6O2ZkOkBpM2pxcnM5cmg5eDMzODU8NEA1NjIxLTEvX14xXmIuXy9gYSNoYDFtMmRza2VgLS1kMS1zcw%3D%3D&vvpl=1&l=202609211138593B2E4E2AB9D5B32E6BFC&btag=e00095000&sp_exp=hash_v0",
    "sourcePageUrl": "https://www.tiktok.com/music/original-sound-7467649576808303377",
    "postCount": 20100,
    "rights": {
      "isOriginal": true,
      "isCommercial": true,
      "isCopyrighted": false
    }
  }
}
```

**Post row fields**

| Field | Type | What it does |
| --- | --- | --- |
| `resultType` | string | Always `post` for a post row. |
| `discoveryKeyword` | string | The keyword that first led to the sound during keyword discovery, when applicable. |
| `sound` | object | Sound data linked to the post. |
| `sound.soundId` | string | TikTok's sound ID. |
| `sound.title` | string | Sound title, when available. |
| `sound.artist` | string | Artist reported for the sound, when available. |
| `sound.album` | string | Album reported for the sound, when available. |
| `sound.durationSeconds` | number | Sound duration in seconds, when available. |
| `sound.artworkUrl` | string | Link to the sound artwork, when available. |
| `sound.audioUrl` | string | TikTok audio reference, when available. This is not a file download. |
| `sound.sourcePageUrl` | string | TikTok page for the sound, when available. |
| `sound.postCount` | integer | Number of posts reported for the sound, when available. |
| `sound.rights` | object | Rights details reported by TikTok, when available. |
| `sound.rights.isOriginal` | boolean | Whether TikTok reports the sound as original. |
| `sound.rights.isCommercial` | boolean | Whether TikTok reports the sound as commercial. |
| `sound.rights.isCopyrighted` | boolean | Whether TikTok reports the sound as copyrighted. |
| `post` | object | Post data reported by TikTok. |
| `post.postId` | string | TikTok's post ID. |
| `post.postUrl` | string | Direct TikTok link to the post. |
| `post.caption` | string | Post caption or text, when available. |
| `post.createdAt` | string | Post creation time in ISO 8601 format, when available. |
| `post.durationSeconds` | number | Post duration in seconds, when available. |
| `post.coverUrl` | string | Link to the post cover image, when available. |
| `post.playbackUrl` | string | TikTok playback or media reference, when available. This is not a file download. |
| `post.hashtags` | array of strings | Hashtags associated with the post, when available. |
| `post.creator` | object | Creator details reported by TikTok, when available. |
| `post.creator.creatorId` | string | TikTok ID of the creator. |
| `post.creator.handle` | string | Creator handle. |
| `post.creator.displayName` | string | Creator display name. |
| `post.creator.profileImageUrl` | string | Link to the creator profile image. |
| `post.creator.followerCount` | integer | Creator follower count reported by TikTok. |
| `post.engagement` | object | Engagement counts reported by TikTok, when available. |
| `post.engagement.viewCount` | integer | Number of views or plays reported for the post. |
| `post.engagement.likeCount` | integer | Number of likes reported for the post. |
| `post.engagement.commentCount` | integer | Number of comments reported for the post. |
| `post.engagement.shareCount` | integer | Number of shares reported for the post. |

**Example post row**

This unshortened row is a genuine post row from a successful TikTok sound page run. The source URLs are public references and are shown as returned.

```json
{
  "resultType": "post",
  "sound": {
    "soundId": "6787016446238017538",
    "title": "All Shades of Blue",
    "artist": "Gregory Alan Isakov",
    "album": "The Weatherman",
    "durationSeconds": 60,
    "artworkUrl": "https://p77-sg.tiktokcdn.com/aweme/720x720/tos-alisg-v-2774/eac52bdb059042baa323c7f7c3b23c2e.jpeg",
    "audioUrl": "https://sf77-ies-music-sg.tiktokcdn.com/obj/tos-alisg-ve-2774/590e1c8f0afe48319a5572f88f9cd6de",
    "sourcePageUrl": "https://www.tiktok.com/music/All-Shades-of-Blue-6787016446238017538",
    "postCount": 66300,
    "rights": {
      "isOriginal": false,
      "isCommercial": false,
      "isCopyrighted": false
    }
  },
  "post": {
    "postId": "7546774934077312287",
    "postUrl": "https://www.tiktok.com/@natalieeab/video/7546774934077312287",
    "caption": "okay WEIRDOOO",
    "createdAt": "2025-09-06T01:01:21.000Z",
    "durationSeconds": 11,
    "coverUrl": "https://p16-common-sign.tiktokcdn-eu.com/tos-useast8-p-0068-tx2/o8fjQIfC06BCdMN3O6CUQckDAIFeIRAwdhDqkE~tplv-tiktokx-origin.image?dr=10395&x-expires=1790164800&x-signature=zRSMVOVEFGqezp6VM4ufpoPcqNw%3D&t=4d5b0474&ps=13740610&shp=81f88b70&shcp=43f4a2f9&idc=no1a",
    "playbackUrl": "https://v16-webapp-prime.tiktok.com/video/tos/alisg/tos-alisg-ve-37c799-sg/oQCRwCfkJAh6gjYmAQF0dDqDBfNOhewEIIC93I/?a=1988&bti=ODszNWYuMDE6&&bt=3423&ft=-Csk_mgdPD12NdWPNn-Ux_D5SY3W3wv257cAp&mime_type=video_mp4&rc=aTc2ZzwzPGczZTVkOzg2NEBpMzo8a3c5cmpyNTMzaTczNEBjMTY1YWItNjIxMjQvMS4vYSNhLmotMmRjY3FhLS1kMTJzcw%3D%3D&expire=1790165073&l=20260921120422BCEAD46B43D9DE30DE47&ply_type=2&policy=2&signature=30631a91bdbca4f3bf610fc68e47fa5f&tk=tt_chain_token&btag=e000b0000",
    "creator": {
      "creatorId": "6738933801970746373",
      "handle": "natalieeab",
      "displayName": "Natalie Abatemarco",
      "profileImageUrl": "https://p16-common-sign.tiktokcdn-eu.com/tos-maliva-avt-0068/472e908bb402d66ca5fe4d97aead398c~tplv-tiktokx-cropcenter:1080:1080.jpeg?dr=10399&refresh_token=b8e653c5&x-expires=1790164800&x-signature=fBRkWYH1HQiiqRJvR0qW%2FHVTn2w%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=81f88b70&idc=no1a",
      "followerCount": 88100
    },
    "engagement": {
      "viewCount": 1900000,
      "likeCount": 243000,
      "commentCount": 994,
      "shareCount": 8066
    }
  }
}
```

#### 💳 Pricing

This Actor uses pay per event. The charged event is one public TikTok post saved to the dataset. Sound-only runs do not create that post event. The current price is shown on the Store page.

#### 🔌 Integrations

Open the default dataset from the Output panel or use its Apify API URL in a data workflow. The structured rows keep source links for later review, while audio and playback URLs remain source references rather than downloaded files.

**Video guide**

https://www.youtube.com/watch?v=bNACk1\_S\_6w\&list=PLObrtcm1Kw6MUrlLNDbK9QRg8VDJg0gOW\&index=4

#### ❓ FAQ

##### Can I collect sounds without posts?

Yes. Choose `Sounds` as the result type. The Actor returns sound metadata without expanding each sound into posts.

##### Can I use sound IDs and sound page URLs?

Yes. Choose one source method per run, then fill `Sound IDs` or `Sound page URLs`. Values in inactive source fields are ignored.

##### How do I find sounds by a word or phrase?

Choose `Keyword`, add one or more values to `Discovery keywords`, and optionally set a region preference. Set `Sounds per keyword` if you want to limit discovery.

##### What happens when the same sound or post matches more than once?

The first eligible occurrence is saved as soon as it is found. If the same source item appears again through another keyword, URL, ID, or similar submitted value, the later match is ignored.

##### Are audio and playback URLs downloaded files?

No. They are source references returned by TikTok. This Actor does not download or store the audio or video files.

##### What happens when a work limit is empty?

An empty `Sounds per keyword` value returns all available matching sounds for each keyword until the source is exhausted. An empty `Posts per sound` value returns all available posts for each sound until the source is exhausted.

##### Are private sounds or posts included?

No. Private or access-restricted TikTok sounds and posts are outside this Actor's scope.

##### How is a post charge counted?

The paid event is one public TikTok post saved to the dataset. Sound-only rows do not use that post event.

### 📝 Changelog

**v0.0** (21-09-2026)

- Initial release.

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~tiktok-music-posts-scraper/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Related Actors

- **[TikTok Search Scraper](https://apify.com/maximedupre/tiktok-search-results-scraper)** searches public TikTok videos by keyword and shows the music attached to each post.
- **[TikTok Profile Videos API Scraper](https://apify.com/maximedupre/tiktok-profile-videos-api)** collects known creators' public uploads with sound details for profile-based research.
- **[TikTok Profile Mention Scraper](https://apify.com/maximedupre/tiktok-profile-mention-scraper)** finds public posts tied to submitted profiles and includes music and engagement context.
- **[TikTok Music Posts Video Scraper](https://apify.com/powerai/tiktok-music-posts-video-scraper)** collects videos that use one specific TikTok sound.
- **[TikTok Music Posts Scraper](https://apify.com/thescrappa/tiktok-music-posts-scraper)** collects public videos linked to selected TikTok music tracks or sounds.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `resultType` (type: `string`):

Choose `Posts` to collect video posts linked to each selected or discovered sound. Choose `Sounds` to return sound metadata without expanding sounds into posts.

## `findBy` (type: `string`):

Choose one source method, then enter values only in its matching field or section. Inactive source fields are ignored.

## `soundIds` (type: `array`):

Enter one or more TikTok sound IDs. Use this field when `Find posts or sounds by` is `Sound IDs`. Values in inactive source fields are ignored.

## `soundUrls` (type: `array`):

Enter one or more public TikTok music or sound page URLs. Use this field when `Find posts or sounds by` is `Sound page URLs`. Values in inactive source fields are ignored.

## `keywords` (type: `array`):

Enter one or more keywords to find matching TikTok sounds. Use this field when `Find posts or sounds by` is `Keyword`. Values in inactive source fields are ignored.

## `region` (type: `string`):

Optional region preference used only for Keyword discovery, such as `US`. Leave it blank to use the source default.

## `maxSoundsPerKeyword` (type: `integer`):

For Keyword discovery, limit how many matching sounds are returned or used for each keyword. This applies to both Posts and Sounds results. Leave it empty to return all available matching sounds for each keyword until the source is exhausted.

## `maxPostsPerSound` (type: `integer`):

For Posts results, limit how many posts are collected for each selected or discovered sound. This field is ignored for Sounds results. Leave it empty to return all available posts for each sound until the source is exhausted.

## Actor input object example

```json
{
  "resultType": "posts",
  "findBy": "soundIds",
  "soundIds": [
    "6787016446238017538"
  ],
  "maxPostsPerSound": 20
}
```

# Actor output Schema

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

Open the collected TikTok music results.

# 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 = {
    "resultType": "posts",
    "findBy": "soundIds",
    "soundIds": [
        "6787016446238017538"
    ],
    "maxPostsPerSound": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/tiktok-music-posts-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 = {
    "resultType": "posts",
    "findBy": "soundIds",
    "soundIds": ["6787016446238017538"],
    "maxPostsPerSound": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("maximedupre/tiktok-music-posts-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 '{
  "resultType": "posts",
  "findBy": "soundIds",
  "soundIds": [
    "6787016446238017538"
  ],
  "maxPostsPerSound": 20
}' |
apify call maximedupre/tiktok-music-posts-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maximedupre/tiktok-music-posts-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/7gsmTr2Ie8DzzrwXf/builds/1l2YsY8uFzPnWEnyE/openapi.json
