Para saber qué vídeos de TikTok mueven tus reproducciones en Spotify, recoge todos los vídeos que usan tu sonido con el endpoint search/videos de TikTok de Scavio y luego lee los comentarios de cada uno para contar cuánta gente pregunta dónde escuchar la canción. Una API te da señales del lado de TikTok (visualizaciones, compartidos, guardados y el texto real de los comentarios), no una cifra de atribución de Spotify. Así que la respuesta honesta a "¿por qué un clip viral solo sumó 168 reproducciones?" es que las vistas no equivalen a intención de escucha, y el único indicador medible en TikTok de esa intención son los comentarios que piden la canción. Este tutorial ordena tus propios posts y los clips de otros que usan tu pista por intención por visualización, para que dejes de adivinar qué formato funciona y copies aquel cuyos comentarios se llenan de "¿qué canción es?". No obtendrás una proporción limpia de vista a reproducción. Lo que obtienes es una lista ordenada de vídeos y estilos que se correlacionan con gente buscando activamente escuchar.
Requisitos previos
- Una clave de API de Scavio (sk_live_...) desde tu panel; las cuentas nuevas reciben 50 créditos gratis. Los endpoints de TikTok cuestan 1 crédito cada uno.
- Python 3.9+ con requests, o Node.js 18+ para la versión en JavaScript.
- Tu nombre de usuario de TikTok y el nombre exacto del sonido o hashtag con el que se publica tu pista.
- Un LLM (Claude o similar) es opcional pero ayuda a clasificar la intención de los comentarios a escala.
Guia paso a paso
Paso 1: Convierte tu usuario en un sec_uid
El endpoint de posts de TikTok necesita un sec_user_id, no un alias. Llama primero al endpoint de perfil con tu usuario y lee data.user.sec_uid de la respuesta. Este es el patrón de dos pasos para cada llamada por usuario en la API de TikTok. Guarda el sec_uid en caché; no cambia, así que no necesitas repetir esta búsqueda.
import requests
HEADERS = {
"Authorization": "Bearer sk_live_...",
"Content-Type": "application/json",
}
resp = requests.post(
"https://api.scavio.dev/api/v1/tiktok/profile",
headers=HEADERS,
json={"username": "your_artist_handle"},
)
sec_uid = resp.json()["data"]["user"]["sec_uid"]
print(sec_uid)Paso 2: Recoge tus propios posts y sus estadísticas
Envía el sec_uid a user/posts con un count para obtener tus vídeos recientes y las estadísticas por vídeo: play_count, share_count, comment_count y digg_count (me gusta). Aquí los guardados y compartidos importan más que las vistas brutas, porque un guardado es la señal de TikTok más cercana a "quiero volver a esta canción". Ordena tus posts por tasa de compartidos y comentarios, no por vistas, y ya verás cuáles de tus clips se comportan distinto.
resp = requests.post(
"https://api.scavio.dev/api/v1/tiktok/user/posts",
headers=HEADERS,
json={"sec_user_id": sec_uid, "count": 30},
)
posts = resp.json()["data"]["videos"]
for v in posts:
s = v["statistics"]
print(v["video_id"], s["play_count"], s["share_count"], s["comment_count"])Paso 3: Encuentra cada vídeo que usa tu sonido
La mayor parte de tu alcance son vídeos de otros que usan tu pista, no los tuyos. Consulta search/videos con el nombre del sonido o un hashtag de marca para reunir el contenido de usuarios. Cada resultado lleva el mismo bloque de estadísticas. Aquí una API supera al scroll manual: obtienes una lista estructurada de clips que nunca hallarías a mano, candidatos ordenados de qué estilo difunde tu canción.
resp = requests.post(
"https://api.scavio.dev/api/v1/tiktok/search/videos",
headers=HEADERS,
json={"query": "your sound name or #yourtrackhashtag", "count": 50},
)
ugc = resp.json()["data"]["videos"]
print(f"found {len(ugc)} videos using the track")Paso 4: Lee los comentarios buscando intención de escucha
Este es el paso que aproxima la conversión. Para los vídeos con más alcance, llama a video/comments y cuenta los comentarios que preguntan dónde escuchar: "¿qué canción es?", "nombre de la canción", "añadir a mi playlist", "¿está en Spotify?". Esa proporción de comentarios de intención frente a las vistas es el mejor indicador de reproducciones que tienes solo con TikTok. Un clip con 50k vistas y 40 comentarios "¿qué canción?" hace más por ti que uno de 2M de vistas sin ninguno.
def intent_comments(video_id):
resp = requests.post(
"https://api.scavio.dev/api/v1/tiktok/video/comments",
headers=HEADERS,
json={"video_id": video_id, "count": 50},
)
comments = resp.json()["data"]["comments"]
cues = ["what song", "name of", "spotify", "playlist", "where can i"]
hits = [c["text"] for c in comments
if any(q in c["text"].lower() for q in cues)]
return len(hits), hitsPaso 5: Ordena por intención por vista y copia al ganador
Puntúa cada vídeo como intent_comments dividido por las vistas. Ordena de mayor a menor. La cima de esa lista es tu plantilla: la duración del gancho, el texto en pantalla, la parte de la canción usada, la llamada a la acción. Sé honesto sobre el techo. La API no puede decirte que ni una sola de esas personas reprodujo la pista. Lo que te dice, de forma repetible, es qué estilos de vídeo hacen que la gente pida la canción, y esa es la variable que controlas la próxima vez que publiques.
scored = []
for v in posts + ugc:
vid = v["video_id"]
views = v["statistics"]["play_count"] or 1
n_intent, _ = intent_comments(vid)
scored.append((vid, n_intent / views, n_intent, views))
scored.sort(key=lambda x: x[1], reverse=True)
for vid, rate, n, views in scored[:5]:
print(f"{vid}: {n} intent / {views} views = {rate:.5f}")Ejemplo en Python
import requests
API_KEY = "sk_live_..."
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
BASE = "https://api.scavio.dev/api/v1/tiktok"
INTENT_CUES = ["what song", "name of", "spotify", "playlist", "where can i"]
def get_sec_uid(username):
resp = requests.post(f"{BASE}/profile", headers=HEADERS,
json={"username": username})
resp.raise_for_status()
return resp.json()["data"]["user"]["sec_uid"]
def get_my_posts(sec_uid, count=30):
resp = requests.post(f"{BASE}/user/posts", headers=HEADERS,
json={"sec_user_id": sec_uid, "count": count})
resp.raise_for_status()
return resp.json()["data"]["videos"]
def search_sound(query, count=50):
resp = requests.post(f"{BASE}/search/videos", headers=HEADERS,
json={"query": query, "count": count})
resp.raise_for_status()
return resp.json()["data"]["videos"]
def intent_comments(video_id, count=50):
resp = requests.post(f"{BASE}/video/comments", headers=HEADERS,
json={"video_id": video_id, "count": count})
resp.raise_for_status()
comments = resp.json()["data"]["comments"]
hits = [c["text"] for c in comments
if any(q in c["text"].lower() for q in INTENT_CUES)]
return len(hits)
def rank_videos(username, sound_query):
sec_uid = get_sec_uid(username)
videos = get_my_posts(sec_uid) + search_sound(sound_query)
scored = []
for v in videos:
vid = v["video_id"]
views = v["statistics"]["play_count"] or 1
n_intent = intent_comments(vid)
scored.append({
"video_id": vid,
"views": views,
"intent": n_intent,
"intent_per_view": n_intent / views,
})
scored.sort(key=lambda r: r["intent_per_view"], reverse=True)
return scored
if __name__ == "__main__":
rows = rank_videos("your_artist_handle", "#yourtrackhashtag")
for r in rows[:5]:
print(f"{r['video_id']}: {r['intent']} intent / "
f"{r['views']} views = {r['intent_per_view']:.5f}")Ejemplo en JavaScript
const API_KEY = "sk_live_...";
const HEADERS = {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
};
const BASE = "https://api.scavio.dev/api/v1/tiktok";
const INTENT_CUES = ["what song", "name of", "spotify", "playlist", "where can i"];
async function post(path, body) {
const resp = await fetch(`${BASE}${path}`, {
method: "POST",
headers: HEADERS,
body: JSON.stringify(body),
});
if (!resp.ok) throw new Error(`${path} ${resp.status}`);
return resp.json();
}
async function getSecUid(username) {
const data = await post("/profile", { username });
return data.data.user.sec_uid;
}
async function getMyPosts(secUid, count = 30) {
const data = await post("/user/posts", { sec_user_id: secUid, count });
return data.data.videos;
}
async function searchSound(query, count = 50) {
const data = await post("/search/videos", { query, count });
return data.data.videos;
}
async function intentComments(videoId, count = 50) {
const data = await post("/video/comments", { video_id: videoId, count });
const comments = data.data.comments;
const hits = comments.filter((c) =>
INTENT_CUES.some((q) => c.text.toLowerCase().includes(q))
);
return hits.length;
}
async function rankVideos(username, soundQuery) {
const secUid = await getSecUid(username);
const videos = [
...(await getMyPosts(secUid)),
...(await searchSound(soundQuery)),
];
const scored = [];
for (const v of videos) {
const views = v.statistics.play_count || 1;
const intent = await intentComments(v.video_id);
scored.push({
videoId: v.video_id,
views,
intent,
intentPerView: intent / views,
});
}
scored.sort((a, b) => b.intentPerView - a.intentPerView);
return scored;
}
rankVideos("your_artist_handle", "#yourtrackhashtag").then((rows) => {
for (const r of rows.slice(0, 5)) {
console.log(
`${r.videoId}: ${r.intent} intent / ${r.views} views = ` +
`${r.intentPerView.toFixed(5)}`
);
}
});Salida esperada
7389201144556677889: 41 intent / 52310 views = 0.00078
7388110233445566778: 12 intent / 48902 views = 0.00025
7390455667788990011: 6 intent / 211487 views = 0.00003
7387009988776655443: 2 intent / 1842009 views = 0.00000
7386554433221100998: 0 intent / 73620 views = 0.00000