Consigue la lista de todos los vídeos de un perfil de TikTok (fecha exacta de publicación, visualizaciones, descripción y enlace) en CSV o texto. Gratis, en tu navegador, con cualquier perfil público.
Funciona con tu perfil y con cualquier perfil público, en tiktok.com desde un navegador de ordenador.
// Responsive Muse · TikTok Profile Video Exporter · v1.0 · 2026-10-22
// Saves every video of a TikTok profile (yours or any public account) to CSV or TXT: upload
// date, views, caption, pinned and link. The exact upload date comes from the video's own ID,
// so nothing extra is loaded. Runs only on a tiktok.com/@profile page; TikTok loads older videos
// while the script scrolls. It makes no network requests of its own and never reads cookies,
// passwords or tokens.
(async () => {
const TOOL = 'Exportar vídeos de TikTok';
const FORMAT = 'csv'; // 'csv' (Excel, Sheets) or 'txt' (one link per line)
const LIMIT = 0; // stop after this many videos (0 = all)
if (!/(^|\.)tiktok\.com$/.test(location.hostname) || !/^\/@[^/]+\/?$/.test(location.pathname)) {
alert('Abre primero un perfil de TikTok, por ejemplo:\nhttps://www.tiktok.com/@nasa');
return;
}
// A small box on the page shows progress and asks before changing anything,
// so you never need to read or edit the console.
const many = (n, word) => `${n} ${n === 1 ? word : ({ canal: 'canales', 'canción': 'canciones', 'publicación': 'publicaciones', 'elemento guardado': 'elementos guardados' })[word] || word + 's'}`; // 1 vídeo, 2 vídeos
const panel = (() => {
const box = document.createElement('div');
box.style.cssText = 'position:fixed;right:16px;bottom:16px;z-index:2147483647;width:340px;max-width:calc(100vw - 32px);' +
'background:#111318;color:#e6e8ee;font:14px/1.5 system-ui,sans-serif;border-radius:12px;padding:16px;' +
'box-shadow:0 8px 30px rgba(0,0,0,.4);text-align:left';
const head = document.createElement('strong');
head.textContent = TOOL;
const msg = document.createElement('p');
msg.style.cssText = 'margin:8px 0 12px;white-space:pre-line';
const row = document.createElement('div');
row.style.cssText = 'display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end';
box.append(head, msg, row);
document.body.append(box);
const button = (label, primary, onClick) => {
const b = document.createElement('button');
b.textContent = label;
b.style.cssText = 'font:600 14px system-ui,sans-serif;padding:8px 14px;border-radius:8px;cursor:pointer;' +
(primary ? 'background:#0f766e;color:#fff;border:1px solid #0f766e' : 'background:none;color:#e6e8ee;border:1px solid #3a3f4b');
b.onclick = onClick;
row.append(b);
};
return {
text(t) { msg.textContent = t; },
ask(t, yes) {
msg.textContent = t;
row.replaceChildren();
return new Promise(r => {
button('Cancelar', false, () => { row.replaceChildren(); r(false); });
button(yes, true, () => { row.replaceChildren(); r(true); });
});
},
stoppable(onStop) { row.replaceChildren(); button('Parar', false, onStop); },
actions(t, list) {
msg.textContent = t;
row.replaceChildren();
list.forEach(([label, primary, run]) => button(label, primary, run));
},
finish(t) { this.actions(t, [['Cerrar', true, () => box.remove()]]); },
close() { box.remove(); },
};
})();
// Offer the result as a downloaded file or as clipboard text (a real click, so it always works)
const deliver = (summary, body, file) => {
const save = () => {
const a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([/\.csv$/.test(file) ? '\ufeff' + body : body], { type: 'text/plain;charset=utf-8' }));
a.download = file;
a.click();
setTimeout(() => URL.revokeObjectURL(a.href), 5000);
panel.text(`${summary}\nGuardado como ${file} (mira tu carpeta de Descargas).`);
};
const copy = () => navigator.clipboard.writeText(body)
.then(() => panel.text(`${summary}\nCopiado. Pégalo en una hoja de cálculo o en una nota.`))
.catch(() => panel.text(`${summary}\nEl navegador ha bloqueado el portapapeles: usa Descargar.`));
panel.actions(summary, [['Cerrar', false, () => panel.close()], ['Copiar', false, copy], ['Descargar', true, save]]);
};
const sleep = ms => new Promise(r => setTimeout(r, ms));
const videos = new Map();
// A TikTok ID starts with the upload time: the first 32 bits are seconds since 1970
const dateOf = id => new Date(Number(BigInt(id) >> 32n) * 1000).toISOString().slice(0, 16).replace('T', ' ');
// The thumbnail's description ends with "created by NAME with SOUND" (in the page's language)
const caption = alt => alt.replace(/\s+(created by|creado por|criado por|créé par|erstellt von|creato da|gemaakt door)\s.*$/i, '').trim();
const collect = () => {
for (const item of document.querySelectorAll('[data-e2e="user-post-item"]')) {
const a = item.querySelector('a[href*="/video/"], a[href*="/photo/"]');
const id = (a?.getAttribute('href').match(/\/(?:video|photo)\/(\d+)/) || [])[1];
if (!id || videos.has(id)) continue;
videos.set(id, {
date: dateOf(id),
views: (item.querySelector('[data-e2e="video-views"]')?.textContent || '').trim(),
pinned: item.querySelector('[data-e2e="video-card-badge"]') ? 'yes' : '',
type: a.getAttribute('href').includes('/photo/') ? 'photo' : 'video',
caption: caption(item.querySelector('img[alt]')?.alt || ''),
url: a.href,
});
if (LIMIT && videos.size >= LIMIT) return;
}
};
// 1. Scroll to the end, collecting as we go, until nothing new appears four times in a row
let stop = false;
panel.stoppable(() => { stop = true; });
let idle = 0;
while (idle < 4 && !stop && !(LIMIT && videos.size >= LIMIT)) {
const before = videos.size;
collect();
window.scrollTo(0, document.documentElement.scrollHeight);
await sleep(1800);
idle = videos.size === before ? idle + 1 : 0;
panel.text(`Recogiendo vídeos… ${videos.size}`);
}
const list = [...videos.values()];
if (!list.length) {
panel.finish('No se han encontrado vídeos. ¿El perfil es privado, o TikTok te pide iniciar sesión o resolver un puzle? Si no, avísanos en responsive-muse.com.');
return 0;
}
// 2. Build the file and offer it (newest first, pinned videos in their real place)
list.sort((x, y) => y.date.localeCompare(x.date));
const cell = v => '"' + String(v).replace(/"/g, '""') + '"';
const body = FORMAT === 'txt'
? list.map(v => v.url).join('\n')
: ['Publicado (UTC),Visualizaciones,Fijado,Tipo,Descripción,URL', ...list.map(v =>
[v.date, v.views, v.pinned, v.type, v.caption, v.url].map(cell).join(','))].join('\n');
const handle = location.pathname.replace(/\W+/g, '');
deliver(`${stop ? 'Parado antes de terminar. ' : ''}Listo: ${many(list.length, 'vídeo')}.`, body, `tiktok-${handle}.${FORMAT}`);
return list.length;
})();
Marcador: arrastra el botón del medio a tu barra de marcadores, abre www.tiktok.com y pulsa el marcador. Ejecuta el mismo script con las opciones de arriba.
- No envía nada a ningún sitio. Sin fetch, XHR ni scripts externos. La única actividad de red es la de www.tiktok.com cargando tu lista.
- No toca tu sesión. No lee cookies, contraseñas, tokens ni el almacenamiento del navegador.
- Solo funciona en www.tiktok.com. En cualquier otra web se detiene antes de hacer nada.
- Corto y legible. 128 líneas comentadas, sin minificar ni ofuscar.
- Muestra su progreso en la página. Un pequeño recuadro te dice qué está haciendo y al final te ofrece Descargar o Copiar.
- El mismo código para todos. SHA-256 de la versión por defecto:
88f3880b0cc211eb…
Compruébalo tú mismo en 30 segundos
- Léelo: todas las líneas están arriba, con comentarios.
- Busca en el código
fetch,XMLHttpRequest,cookie,localStorageoeval. No aparece ninguna. - Abre la pestaña Red (Network) antes de ejecutarlo: solo verás peticiones a www.tiktok.com.
Cómo usarlo
- Abre el perfil en tiktok.com desde el ordenador, por ejemplo
tiktok.com/@nasa. - Abre la consola: F12 o Ctrl+Mayús+J (Cmd+Opción+J en Mac). Si Chrome te lo pide, escribe
permitir pegar(oallow pastingsi lo tienes en inglés) y pulsa Enter. - Elige las opciones, copia el script, pégalo en la consola y pulsa Enter. Al terminar aparece un recuadro: pulsa Descargar (o Copiar).
La fecha exacta de cada vídeo
TikTok no muestra la fecha en la cuadrícula del perfil, pero la guarda dentro del ID de cada vídeo. El script la lee de ahí, así que obtienes el día y la hora (UTC) de publicación sin abrir los vídeos uno a uno.
Preguntas frecuentes
¿De dónde sale la fecha exacta de publicación?
Del propio ID del vídeo: TikTok genera cada ID a partir del momento en que se publicó, así que el script puede leer la fecha y la hora (UTC) sin abrir cada vídeo.
¿Por qué algunas descripciones salen cortadas?
La cuadrícula del perfil solo trae el principio de las descripciones largas. Abre el vídeo si necesitas el texto completo.
¿Puedo exportar «me gusta» o comentarios?
Con esta herramienta no: lista los vídeos de un perfil. Las visualizaciones son la cifra que TikTok muestra en cada miniatura (por ejemplo 1.7M).
TikTok me pide resolver un puzle
TikTok a veces comprueba si eres un bot cuando te desplazas por perfiles muy largos. Resuélvelo y vuelve a ejecutar el script: empieza de nuevo y recoge todo lo cargado.
Más herramientas gratis
YouTube
8 herramientas- Vaciar Ver más tarde
- Anular todas las suscripciones
- Quitar todos los «me gusta»
- Exportar Ver más tarde
- Exportar publicaciones guardadas
- Borrar todos los comentarios
TikTok
1 herramienta- Exportar vídeos de un perfil
Amazon
2 herramientas- Exportar historial de pedidos
- Exportar lista de deseos
X / Twitter
3 herramientas- Exportar guardados
- Quitar todos los «me gusta»
- Borrar todos los guardados
Chats de IA
4 herramientas- Exportar chat de ChatGPT
- Exportar chat de Claude
- Exportar chat de Gemini
- Exportar hilo de Perplexity
Google Maps
1 herramienta- Exportar reseñas de Google Maps
Steam
1 herramienta- Exportar lista de deseados de Steam
Apple Music
1 herramienta- Exportar playlist de Apple Music
