El contenido generado por el usuario en TikTok es una de las formas más auténticas de prueba social para las marcas. Recopilar UGC a escala (menciones de marca, reseñas de productos, videos de unboxing y entradas de desafíos de hashtag) requiere monitorear múltiples vectores de búsqueda simultáneamente. Este tutorial crea un canal de recopilación de UGC automatizado utilizando la API Scavio TikTok que busca videos de marcas, monitorea hashtags y cataloga el contenido de los creadores. Cada llamada a la API cuesta 1 crédito ($0,005) y una ejecución de cobro diaria utiliza entre 5 y 10 créditos.
Requisitos previos
- Python 3.9+ instalado
- solicita biblioteca instalada
- Una clave API de Scavio de scavio.dev
- Nombre de marca y hashtags relevantes para monitorear
Guia paso a paso
Paso 1: Buscar vídeos relacionados con la marca
Busque en TikTok videos que mencionen su marca o producto. Esto detecta menciones orgánicas que no utilizan el hashtag de su marca.
import requests, os
API_KEY = os.environ['SCAVIO_API_KEY']
TIKTOK_URL = 'https://api.scavio.dev/api/v1/tiktok'
def search_brand_videos(brand: str, count: int = 30) -> list:
resp = requests.post(f'{TIKTOK_URL}/search/videos',
headers={'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'},
json={'keyword': brand, 'count': count, 'cursor': 0})
resp.raise_for_status()
videos = resp.json().get('data', {}).get('videos', [])
return [{
'id': v.get('id', ''),
'author': v.get('author', {}).get('uniqueId', ''),
'author_followers': v.get('author', {}).get('stats', {}).get('followerCount', 0),
'desc': v.get('desc', ''),
'plays': v.get('stats', {}).get('playCount', 0),
'likes': v.get('stats', {}).get('diggCount', 0),
'comments': v.get('stats', {}).get('commentCount', 0),
'shares': v.get('stats', {}).get('shareCount', 0),
'create_time': v.get('createTime', 0),
'source': 'brand_search'
} for v in videos]
videos = search_brand_videos('YourBrand')
print(f'Found {len(videos)} brand mention videos')Paso 2: Recopilar entradas de campaña de hashtag
Supervise los hashtags de su marca para recopilar UGC específicos de la campaña. Se pueden rastrear varios hashtags en una sola ejecución.
def collect_hashtag_ugc(hashtags: list, count_per_tag: int = 20) -> list:
all_videos = []
for hashtag in hashtags:
resp = requests.post(f'{TIKTOK_URL}/hashtag/posts',
headers={'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'},
json={'hashtag': hashtag, 'count': count_per_tag, 'cursor': 0})
videos = resp.json().get('data', {}).get('videos', [])
for v in videos:
all_videos.append({
'id': v.get('id', ''),
'author': v.get('author', {}).get('uniqueId', ''),
'author_followers': v.get('author', {}).get('stats', {}).get('followerCount', 0),
'desc': v.get('desc', ''),
'plays': v.get('stats', {}).get('playCount', 0),
'likes': v.get('stats', {}).get('diggCount', 0),
'hashtag': hashtag,
'source': 'hashtag_search'
})
return all_videos
hashtag_videos = collect_hashtag_ugc(['yourbrand', 'yourbrandchallenge'])
print(f'Found {len(hashtag_videos)} hashtag videos')Paso 3: Deduplicar y clasificar UGC
Combine los resultados de la búsqueda de marcas y la búsqueda de hashtags, elimine duplicados y clasifique cada vídeo por tipo de contenido: reseña, unboxing, tutorial o mención general.
def classify_ugc(video: dict) -> str:
desc = video.get('desc', '').lower()
if any(w in desc for w in ['review', 'honest', 'rating', 'worth it']):
return 'review'
if any(w in desc for w in ['unbox', 'unboxing', 'first look', 'opening']):
return 'unboxing'
if any(w in desc for w in ['tutorial', 'how to', 'tip', 'hack']):
return 'tutorial'
if any(w in desc for w in ['haul', 'shopping', 'bought']):
return 'haul'
return 'mention'
def dedupe_and_classify(videos: list) -> list:
seen_ids = set()
unique = []
for v in videos:
if v['id'] not in seen_ids:
seen_ids.add(v['id'])
v['content_type'] = classify_ugc(v)
unique.append(v)
return unique
all_videos = search_brand_videos('YourBrand') + hashtag_videos
ugc = dedupe_and_classify(all_videos)
print(f'{len(ugc)} unique UGC videos')
from collections import Counter
types = Counter(v['content_type'] for v in ugc)
for t, count in types.most_common():
print(f' {t}: {count}')Paso 4: Calificar y clasificar UGC por valor de reenvío
Califique cada pieza de UGC según la participación, el número de seguidores del creador y el tipo de contenido. Las puntuaciones más altas significan mejores candidatos para volver a publicar o destacar.
def score_ugc(video: dict) -> float:
score = 0
# Engagement score (0-40)
engagement = video['likes'] + video.get('comments', 0) + video.get('shares', 0)
if engagement > 10000: score += 40
elif engagement > 1000: score += 30
elif engagement > 100: score += 20
else: score += 10
# Creator reach (0-30)
followers = video.get('author_followers', 0)
if followers > 100000: score += 30
elif followers > 10000: score += 20
elif followers > 1000: score += 10
# Content type bonus (0-30)
type_bonus = {'review': 30, 'unboxing': 25, 'tutorial': 20, 'haul': 15, 'mention': 10}
score += type_bonus.get(video.get('content_type', 'mention'), 10)
return score
def rank_ugc(videos: list) -> list:
for v in videos:
v['ugc_score'] = score_ugc(v)
ranked = sorted(videos, key=lambda v: v['ugc_score'], reverse=True)
return ranked
ranked = rank_ugc(ugc)
print('Top UGC candidates:')
for v in ranked[:5]:
print(f' [{v["ugc_score"]}] @{v["author"]} ({v["content_type"]}): '
f'{v["plays"]:,} plays, {v["likes"]:,} likes')Paso 5: Guardar colección con historial diario
Almacene cada ejecución de colección con marcas de tiempo para que pueda realizar un seguimiento de los nuevos UGC que aparecen a lo largo del tiempo y nunca perderse contenido nuevo.
import json
from datetime import date, datetime
def save_collection(videos: list, brand: str) -> str:
filename = f'ugc_{brand}_{date.today()}.json'
collection = {
'brand': brand,
'collected_at': datetime.now().isoformat(),
'total_videos': len(videos),
'by_type': dict(Counter(v.get('content_type', 'unknown') for v in videos)),
'top_10': [{
'id': v['id'],
'author': v['author'],
'content_type': v.get('content_type'),
'ugc_score': v.get('ugc_score', 0),
'plays': v['plays'],
'likes': v['likes'],
'desc': v['desc'][:100]
} for v in videos[:10]],
'credits_used': 3, # 1 brand search + 2 hashtag searches
'cost': '$0.015'
}
with open(filename, 'w') as f:
json.dump(collection, f, indent=2)
print(f'Saved {len(videos)} UGC videos to {filename}')
print(f'Credits: {collection["credits_used"]} (${collection["credits_used"] * 0.005:.3f})')
return filename
save_collection(ranked, 'YourBrand')Ejemplo en Python
import os, requests, json
from collections import Counter
from datetime import date
API_KEY = os.environ['SCAVIO_API_KEY']
TT = 'https://api.scavio.dev/api/v1/tiktok'
def tt(endpoint, body):
return requests.post(f'{TT}/{endpoint}',
headers={'Authorization': f'Bearer {API_KEY}', 'Content-Type': 'application/json'},
json=body).json()
def collect_ugc(brand, hashtags):
# Brand search
brand_vids = tt('search/videos', {'keyword': brand, 'count': 30, 'cursor': 0})
videos = brand_vids.get('data', {}).get('videos', [])
# Hashtag search
for tag in hashtags:
tag_vids = tt('hashtag/posts', {'hashtag': tag, 'count': 20, 'cursor': 0})
videos.extend(tag_vids.get('data', {}).get('videos', []))
# Dedupe
seen = set()
unique = [v for v in videos if v.get('id') not in seen and not seen.add(v['id'])]
print(f'Collected {len(unique)} unique UGC videos')
for v in sorted(unique, key=lambda x: x.get('stats', {}).get('diggCount', 0), reverse=True)[:5]:
print(f' @{v.get("author", {}).get("uniqueId", "")}: {v.get("stats", {}).get("playCount", 0):,} plays')
collect_ugc('YourBrand', ['yourbrand', 'yourbrandchallenge'])Ejemplo en JavaScript
const API_KEY = process.env.SCAVIO_API_KEY;
const TT = 'https://api.scavio.dev/api/v1/tiktok';
async function tt(endpoint, body) {
const r = await fetch(`${TT}/${endpoint}`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
return r.json();
}
async function collectUgc(brand, hashtags) {
const brandVids = await tt('search/videos', { keyword: brand, count: 30, cursor: 0 });
let videos = brandVids.data?.videos || [];
for (const tag of hashtags) {
const tagVids = await tt('hashtag/posts', { hashtag: tag, count: 20, cursor: 0 });
videos.push(...(tagVids.data?.videos || []));
}
const seen = new Set();
const unique = videos.filter(v => v.id && !seen.has(v.id) && seen.add(v.id));
console.log(`Collected ${unique.length} unique UGC videos`);
unique.sort((a, b) => (b.stats?.diggCount || 0) - (a.stats?.diggCount || 0))
.slice(0, 5).forEach(v => {
console.log(` @${v.author?.uniqueId}: ${(v.stats?.playCount || 0).toLocaleString()} plays`);
});
}
collectUgc('YourBrand', ['yourbrand', 'yourbrandchallenge']);Salida esperada
Found 28 brand mention videos
Found 35 hashtag videos
63 unique UGC videos
review: 8
unboxing: 5
tutorial: 3
haul: 4
mention: 43
Top UGC candidates:
[85] @creator1 (review): 234,000 plays, 18,500 likes
[75] @creator2 (unboxing): 156,000 plays, 12,300 likes
[70] @creator3 (tutorial): 89,000 plays, 7,200 likes
Saved 63 UGC videos to ugc_YourBrand_2026-05-13.json
Credits: 3 ($0.015)