Meta's Instagram Audio API finds songs and original sounds to add to a reel you post from a Business or Creator account. Nothing in it lists the reels that already use a song or counts them. Our Instagram API reads a song's public audio page: how many reels use it, and the reels themselves with plays, likes and authors.
What Meta's Audio API is for
The Instagram Audio API is part of content publishing. It needs an Instagram Business or Creator account with a connected Facebook Page, the instagram_basic and instagram_content_publish permissions and a user token from Facebook Login; it is not supported with Instagram Login. A search returns tracks with audio_id, title, artist and duration, limited to audio cleared for third-party use, so the selection "may vary from what appears in the native app." It returns no reel counts and no reels.
Song data with ToolzerHub
We make ToolzerHub. Our Instagram API returns public Instagram profiles, posts, reels, hashtags and audio as JSON with one API key. Two routes cover this, each 3 credits a call:
/v1/instagram/music/search: tracks for akeyword, withaudio_id, title, artist and duration/v1/instagram/music/posts: one track's reel count and 12 reels a call, bymusic_id; passpaging_info.max_idasmax_idfor the next 12
export TOOLZERHUB_API_KEY=your_key
curl -H "x-api-key: $TOOLZERHUB_API_KEY" \
"https://api.toolzerhub.com/v1/instagram/music/posts?music_id=1467739367151376"
Espresso's audio page in data, trimmed to one reel:
{
"media_count": {"clips_count": 2564602, "photos_count": 0},
"metadata": {"music_info": {"music_asset_info": {"title": "Espresso", "display_artist": "Sabrina Carpenter"}}},
"items": [
{"media": {
"code": "DcWlr7Xvfas",
"taken_at": 1787424436,
"product_type": "clips",
"play_count": 1268230,
"like_count": 47419,
"comment_count": 724,
"user": {"username": "adrianglezbencomo", "is_verified": true}
}}
],
"paging_info": {"max_id": "GvYP2Nrv...", "more_available": true}
}
code builds the reel link, instagram.com/reel/<code>/, and taken_at is Unix seconds. play_count is exact, where TikTok rounds plays. The reel count grows between calls: the table's run, an hour later, read 2,564,645 for Espresso. The track block also carries the artist's Instagram username and a Spotify track ID.
Track how a song is used on Instagram
The script takes song names, audio links or audio IDs. A name is searched and the first track kept; the first result can be another song with the same title, so add the artist and check the printed title. It reads the pages of reels you ask for and writes one row per reel with its author, plays, likes and comments. For each song it prints the reel count, the median plays of the reels it read and how many had under 10,000 plays. Install requests (pip install requests) and save it as instagram_music.py.
import csv
import os
import re
import statistics
import sys
import time
from datetime import datetime, timezone
import requests
API = "https://api.toolzerhub.com/v1/instagram/music"
HEADERS = {"x-api-key": os.environ.get("TOOLZERHUB_API_KEY", "")}
FIELDS = ["track", "artist", "audio_id", "rank", "code", "posted_at", "author", "verified", "plays", "likes",
"comments", "url"]
def get(op, params, tries=3):
# Retry rate limits, server errors and dropped connections.
for attempt in range(tries):
last = attempt == tries - 1
try:
r = requests.get(f"{API}/{op}", headers=HEADERS, params=params, timeout=120)
except requests.RequestException:
if last:
raise
time.sleep(5 * (attempt + 1))
continue
if r.status_code in (429, 500, 502, 503, 504) and not last:
time.sleep(5 * (attempt + 1))
continue
r.raise_for_status()
return r.json()["data"]
def audio_id(ref):
# An audio link or ID is used as is; anything else is searched and the first track kept.
ids = re.findall(r"\d{12,}", ref)
if ids:
return ids[-1]
return get("search", {"keyword": ref})["items"][0]["audio_id"]
def main(tracks, pages="3", out="instagram_music.csv"):
with open(out, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=FIELDS)
writer.writeheader()
for ref in filter(None, (t.strip() for t in tracks.split(";"))):
music_id, reels, seen, cursor, page = audio_id(ref), [], set(), None, {}
for _ in range(int(pages)):
data = get("posts", {"music_id": music_id, **({"max_id": cursor} if cursor else {})})
page = page or data
for item in data.get("items") or []:
m = item["media"]
if m["code"] not in seen:
seen.add(m["code"])
reels.append(m)
paging = data.get("paging_info") or {}
if not paging.get("more_available"):
break
cursor = paging["max_id"]
info = page["metadata"]["music_info"]["music_asset_info"]
total = (page.get("media_count") or {}).get("clips_count")
for rank, m in enumerate(reels, 1):
writer.writerow({
"track": info["title"], "artist": info["display_artist"], "audio_id": music_id, "rank": rank,
"code": m["code"], "posted_at": datetime.fromtimestamp(m["taken_at"], timezone.utc).isoformat(),
"author": m["user"]["username"], "verified": m["user"].get("is_verified"),
"plays": m.get("play_count"), "likes": m.get("like_count"), "comments": m.get("comment_count"),
"url": f"https://www.instagram.com/reel/{m['code']}/",
})
plays = [m.get("play_count") or 0 for m in reels]
print(f"{info['title']} by {info['display_artist']}: {total or 0:,} reels; first {len(reels)} read, "
f"median {statistics.median(plays or [0]):,.0f} plays, "
f"{sum(p < 10_000 for p in plays)} under 10,000 plays")
if __name__ == "__main__":
if len(sys.argv) < 2:
sys.exit('usage: python instagram_music.py "Espresso Sabrina Carpenter;APT. ROSE" [pages] [out.csv]')
if not HEADERS["x-api-key"]:
sys.exit("set TOOLZERHUB_API_KEY first")
main(*sys.argv[1:])
What four songs showed
Three pages each for four songs made 16 calls in 75 seconds and saved 144 reels:
python instagram_music.py "Housewife Tate McRae;Coming Up Roses Harry Styles;Espresso Sabrina Carpenter;APT. ROSE Bruno Mars" 3
| Song | Reels using it | Reels read | Median plays | 1 million plays or more | From verified accounts | Median age of reels |
|---|---|---|---|---|---|---|
| Housewife, Tate McRae | 249,750 | 36 | 312,488 | 6 | 16 | 15.9 days |
| Coming Up Roses, Harry Styles | 57,157 | 36 | 223,918 | 4 | 8 | 11.6 days |
| Espresso, Sabrina Carpenter | 2,564,645 | 36 | 47,762 | 2 | 10 | 15.4 days |
| APT., ROSÉ and Bruno Mars | 5,534,266 | 36 | 71,572 | 2 | 15 | 17 days |
The audio page leads with recent reels, not the biggest ones: the median reel was 11.6 to 17 days old, and plays came in no order. On Espresso and APT., with millions of reels each, the median reel read had 47,762 and 71,572 plays. The two songs with the fewest reels had the most plays per reel: Housewife's 36 had a median of 312,488, and Tate McRae's own reel topped them at 16,533,106.
The same songs on TikTok, from our TikTok sound API post the same day: 520,036 TikTok videos use Housewife against 249,750 reels, and 221,942 use Coming Up Roses against 57,157. On Coming Up Roses the two pages answer different questions: TikTok's led with videos a median of 184.6 days old, every one past a million plays, while Instagram's led with reels a median of 11.6 days old.
What it costs
A song at three pages is 12 credits: 3 for the search and 3 per page of 12 reels, or 9 with an audio link. The 100 free credits a month cover eight songs at that depth; $19 buys 10,000 credits that never expire, and plans for higher volume cover daily tracking of a release. Set your key and the first song is a CSV in under a minute.
For posts under a hashtag, see the Instagram hashtag API. For one creator's reels, see the Instagram reels API.
We are not affiliated with Instagram or Meta.