jackwener/OpenCLI · error · Error

Could not parse profile data

Error message

Could not parse profile data

What it means

After fetching the profile HTML successfully, the script searches for the __UNIVERSAL_DATA_FOR_REHYDRATION__ script tag that carries TikTok's JSON state. If the marker string is absent (indexOf returns -1) it throws 'Could not parse profile data'. This means the page loaded but did not contain the expected embedded data blob.

Source

Thrown at clis/tiktok/profile.js:34

    columns: [
        'username',
        'name',
        'followers',
        'following',
        'likes',
        'videos',
        'verified',
        'bio',
    ],
    pipeline: [
        { navigate: { url: 'https://www.tiktok.com/explore', settleMs: 5000 } },
        { evaluate: `(async () => {
  const username = \${{ args.username | json }};
  const res = await fetch('https://www.tiktok.com/@' + encodeURIComponent(username), { credentials: 'include' });
  if (!res.ok) throw new Error('User not found: ' + username);
  const html = await res.text();
  const idx = html.indexOf('__UNIVERSAL_DATA_FOR_REHYDRATION__');
  if (idx === -1) throw new Error('Could not parse profile data');
  const start = html.indexOf('>', idx) + 1;
  const end = html.indexOf('</script>', start);
  const data = JSON.parse(html.substring(start, end));
  const ud = data['__DEFAULT_SCOPE__'] && data['__DEFAULT_SCOPE__']['webapp.user-detail'];
  const u = ud && ud.userInfo && ud.userInfo.user;
  const s = ud && ud.userInfo && ud.userInfo.stats;
  if (!u) throw new Error('User not found: ' + username);
  return [{
    username: u.uniqueId || username,
    name: u.nickname || '',
    bio: (u.signature || '').replace(/\\n/g, ' ').substring(0, 120),
    followers: s && s.followerCount || 0,
    following: s && s.followingCount || 0,
    likes: s && s.heartCount || 0,
    videos: s && s.videoCount || 0,
    verified: u.verified ? 'Yes' : 'No',
  }];
})()

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry with a logged-in, warmed browser session and residential IP to bypass bot/consent interstitials
  2. Capture and inspect the returned HTML to see what page TikTok actually served
  3. Check the library for updates — the marker may have been renamed by TikTok and selectors patched
  4. Fall back to another data source or the mobile API for profile info

Example fix

// before
const data = await getProfile(username); // throws Could not parse profile data
// after
try {
  const data = await getProfile(username);
} catch (e) {
  if (/Could not parse profile data/.test(e.message)) {
    console.error('TikTok page had no rehydration data (likely bot wall); retry with warm session');
  } else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

const html = await (await fetch('https://www.tiktok.com/@' + username, { credentials: 'include' })).text();
if (!html.includes('__UNIVERSAL_DATA_FOR_REHYDRATION__')) {
  throw new Error('TikTok served a page without profile data (bot wall or markup change)');
}

Type guard

function hasRehydrationData(html) {
  return typeof html === 'string' && html.indexOf('__UNIVERSAL_DATA_FOR_REHYDRATION__') !== -1;
}

Try / catch

let profile;
for (let attempt = 0; attempt < 3; attempt++) {
  try {
    profile = await run('tiktok profile', { username });
    break;
  } catch (e) {
    if (!/Could not parse profile data/.test(e.message) || attempt === 2) throw e;
    await new Promise(r => setTimeout(r, 5000 * (attempt + 1)));
  }
}

Prevention

When it happens

Trigger: The fetched HTML for tiktok.com/@<username> lacks the __UNIVERSAL_DATA_FOR_REHYDRATION__ script — typically a login wall, captcha/bot-check page, consent/redirect interstitial, or a TikTok markup change removed/renamed the global data key.

Common situations: Datacenter IP or headless browser flagged by TikTok; cookie-consent banner intercepting; TikTok renaming the rehydration global in a frontend deploy; response being an SPA shell without SSR data.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/33fe805e92162206. Report an issue: GitHub.