How to scrape TikTok comment replies with JavaScript

A JavaScript script that fetches TikTok comment replies, pages through the results and saves them to a file.

Preview
The API is in early access. Ask for a key; the examples use api.socialscrape.io.

Set up

You need Node 18 or newer. It has fetch built in, so there is nothing to install.

export SOCIALSCRAPE_API_KEY=ss_live_...

The script

Save as scrape.mjs and run node scrape.mjs. It calls GET /v1/tiktok/video/comment/replies.

scrape.mjs
import { writeFileSync } from "node:fs";

const BASE = "https://api.socialscrape.io/v1/tiktok/video/comment/replies";
const KEY = process.env.SOCIALSCRAPE_API_KEY;
const PARAMS = {
  url: "https://www.tiktok.com/@khaby.lame/video/7137423965982592302",
  comment_id: "7137510823549272878",
};
const MAX_ITEMS = 100;

// Follow a path through nested objects; undefined if any step is missing or null.
const pick = (obj, ...path) => path.reduce((o, k) => (o == null ? undefined : o[k]), obj);
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// One request. Failures cost nothing; retry the ones the API marks retryable.
async function get(params) {
  for (let attempt = 0; attempt < 3; attempt++) {
    const url = new URL(BASE);
    url.search = new URLSearchParams(params).toString();
    const body = await (await fetch(url, { headers: { "x-api-key": KEY } })).json();
    if (body.ok) return body;
    const { code, message, retryable } = body.error;
    if (!retryable || attempt === 2) throw new Error(`${code}: ${message}`);
    await sleep(2 ** attempt * 1000);
  }
}

let items = [];
let params = { ...PARAMS };
let body;
while (items.length < MAX_ITEMS) {
  body = await get(params);
  items.push(...body.data.items);
  if (!body.has_more) break;
  params = { ...params, cursor: body.cursor };
}
items = items.slice(0, MAX_ITEMS);

writeFileSync("out.json", JSON.stringify(items, null, 2));
for (const item of items.slice(0, 5)) {
  console.log(pick(item, "text"), pick(item, "id"), pick(item, "stats", "likes"));
}
console.log(`saved ${items.length} items to out.json, credits left: ${body.credits_remaining}`);

How it works

  1. get() sends one request and retries the failures the API marks retryable. A failed request costs nothing.
  2. The loop follows cursor until has_more is false or 100 items are collected. Each page costs its own price.
  3. pick() reads nested fields and gives undefined instead of crashing when the platform returned null.
  4. Items go to out.json, and the first five are printed.

What you get back

These fields come from a recorded sample. The full field list is on the endpoint page.

Fields in the scriptSample
{
  "text": "No",
  "id": "7137827034517406506",
  "stats": {
    "likes": 16
  }
}

The short version

Without paging, saving or retries, the request is this.

const url = new URL("https://api.socialscrape.io/v1/tiktok/video/comment/replies");
url.search = new URLSearchParams({
  url: "https://www.tiktok.com/@khaby.lame/video/7137423965982592302",
  comment_id: "7137510823549272878",
}).toString();
const res = await fetch(url, {
  headers: { "x-api-key": process.env.SOCIALSCRAPE_API_KEY },
});
const body = await res.json();

if (body.ok) {
  console.log(body.data);
} else {
  console.error(body.error.code, body.error.message);
}

With the SDK

The JavaScript client does the retries and the paging for you. It is in preview and not published yet.

import { SocialScrape } from "socialscrape";

const client = new SocialScrape(); // reads SOCIALSCRAPE_API_KEY

for await (const item of client.paginate(client.tiktok.videoCommentReplies, { url: "https://www.tiktok.com/@khaby.lame/video/7137423965982592302", comment_id: "7137510823549272878" }, { maxItems: 100 })) {
  console.log(item.text);
}

What it costs

1 credit. A failed request costs nothing. Add max_age_days to reuse a cached result for 0 credits. Results are kept 30 days.

Next

Get a key.

Early access keys go to developers and agent builders first.

Get early access