jackwener/OpenCLI · error · Error

Like button not found - make sure you are logged in

Error message

Like button not found - make sure you are logged in

What it means

The unlike script queries [data-e2e="like-icon"] on the video page and throws 'Like button not found - make sure you are logged in' if it is absent. Like controls only render for authenticated viewers on a fully loaded video page, so a missing element points to auth, rendering, or selector drift. The script otherwise relies on aria-label/color to detect the liked state.

Source

Thrown at clis/tiktok/unlike.js:17

import { cli } from '@jackwener/opencli/registry';
cli({
    site: 'tiktok',
    name: 'unlike',
    access: 'write',
    description: 'Unlike a TikTok video',
    domain: 'www.tiktok.com',
    args: [
        { name: 'url', required: true, positional: true, help: 'TikTok video URL' },
    ],
    columns: ['status', 'likes', 'url'],
    pipeline: [
        { navigate: { url: '${{ args.url }}', settleMs: 6000 } },
        { evaluate: `(async () => {
  const url = \${{ args.url | json }};
  const btn = document.querySelector('[data-e2e="like-icon"]');
  if (!btn) throw new Error('Like button not found - make sure you are logged in');
  const container = btn.closest('button') || btn.closest('[role="button"]') || btn;
  const aria = (container.getAttribute('aria-label') || '').toLowerCase();
  const color = window.getComputedStyle(btn).color;
  const isLiked = aria.includes('unlike') || aria.includes('取消点赞') ||
                  (color && (color.includes('255, 65') || color.includes('fe2c55')));
  if (!isLiked) {
    const count = document.querySelector('[data-e2e="like-count"]');
    return [{ status: 'Not liked', likes: count ? count.textContent.trim() : '-', url: url }];
  }
  container.click();
  await new Promise(r => setTimeout(r, 2000));
  const count = document.querySelector('[data-e2e="like-count"]');
  return [{ status: 'Unliked', likes: count ? count.textContent.trim() : '-', url: url }];
})()
` },
    ],
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log into TikTok in the automation browser (persist cookies) and retry
  2. Verify the URL opens a playable video page and the like icon exists in DevTools; update the selector if TikTok renamed it
  3. Increase the settle/wait time so the page fully renders before querying
  4. Use canonical www.tiktok.com/@user/video/<id> URLs instead of short links

Example fix

// before
await run('tiktok unlike', { url: shortUrl });
// after
const canonical = await resolveShortLink(shortUrl); // www.tiktok.com/@user/video/<id>
await run('tiktok unlike', { url: canonical });
Defensive patterns

Strategy: validation

Validate before calling

await page.goto(url, { waitUntil: 'networkidle' });
await page.waitForSelector('[data-e2e="like-icon"]', { timeout: 10000 })
  .catch(() => { throw new Error('Like icon never rendered — check login session and video URL'); });

Type guard

function likeButtonExists(doc) {
  return Boolean(doc.querySelector('[data-e2e="like-icon"]'));
}

Try / catch

try {
  await run('tiktok unlike', { url });
} catch (e) {
  if (/Like button not found/.test(e.message)) {
    console.error('Not logged in, video unavailable, or like selector changed');
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling the unlike command on a URL where no [data-e2e="like-icon"] element exists: unauthenticated session, video removed/private/region-blocked, page not rendered within the 6s settle, or TikTok changed the data-e2e attribute.

Common situations: Expired cookies; headless run without login state; short-share links landing on interstitials; TikTok A/B tests renaming data-e2e attributes; photo-post layouts that omit the video like icon.

Related errors


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