jackwener/OpenCLI · error · Error
Favorites button not found - make sure you are logged in
Error message
Favorites button not found - make sure you are logged in
What it means
The save-to-favorites script looks for the bookmark button via [data-e2e="bookmark-icon"] or [data-e2e="collect-icon"] and throws if neither exists, telling you to make sure you are logged in. The button only renders for authenticated users viewing an eligible video, so its absence usually means an auth or rendering problem rather than a logic bug.
Source
Thrown at clis/tiktok/save.js:18
import { cli } from '@jackwener/opencli/registry';
cli({
site: 'tiktok',
name: 'save',
access: 'write',
description: 'Add a TikTok video to Favorites',
domain: 'www.tiktok.com',
args: [
{ name: 'url', required: true, positional: true, help: 'TikTok video URL' },
],
columns: ['status', 'url'],
pipeline: [
{ navigate: { url: '${{ args.url }}', settleMs: 6000 } },
{ evaluate: `(async () => {
const url = \${{ args.url | json }};
const btn = document.querySelector('[data-e2e="bookmark-icon"]') ||
document.querySelector('[data-e2e="collect-icon"]');
if (!btn) throw new Error('Favorites 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();
if (aria.includes('remove from favorites') || aria.includes('取消收藏')) {
return [{ status: 'Already in Favorites', url: url }];
}
container.click();
await new Promise(r => setTimeout(r, 2000));
return [{ status: 'Added to Favorites', url: url }];
})()
` },
],
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Log into TikTok in the automation browser and persist cookies, then retry
- Increase the wait/settle time so the video page fully renders before querying the button
- Open the URL manually and inspect whether [data-e2e="bookmark-icon"] or [data-e2e="collect-icon"] exists; if not, the selectors need updating
- Verify the video URL resolves to a playable video page, not an interstitial or removed content
Example fix
// before
await run('tiktok save', { url: 'https://vm.tiktok.com/XYZ/' });
// after
await run('tiktok save', { url: 'https://www.tiktok.com/@user/video/1234567890' }); // resolved, logged-in session Defensive patterns
Strategy: validation
Validate before calling
await page.goto(url, { waitUntil: 'networkidle' });
await page.waitForSelector('[data-e2e="bookmark-icon"], [data-e2e="collect-icon"]', { timeout: 10000 })
.catch(() => { throw new Error('Bookmark button never rendered — check login and URL'); }); Type guard
function bookmarkButtonExists(doc) {
return Boolean(doc.querySelector('[data-e2e="bookmark-icon"]') || doc.querySelector('[data-e2e="collect-icon"]'));
} Try / catch
try {
await run('tiktok save', { url });
} catch (e) {
if (/Favorites button not found/.test(e.message)) {
console.error('Not logged in or page did not render the bookmark button; verify session and URL');
} else {
throw e;
}
} Prevention
- Always run with a persisted, logged-in TikTok session for favorite actions
- Use canonical video URLs, not short share links
- Wait for network idle or the selector itself rather than a fixed settle time
- Periodically verify data-e2e attribute names against a live page
When it happens
Trigger: Calling the save command with a URL whose page never rendered the bookmark button: not logged in, video unavailable/deleted/region-blocked, page still loading past the 6s settle, or TikTok changed the data-e2e attribute names.
Common situations: Stale/expired session cookies; running headless without login state; using a link format (e.g. short vm.tiktok.com link) that lands on an interstitial; TikTok A/B test renaming data-e2e attributes.
Related errors
- Like button not found - make sure you are logged in
- BUTTON_NOT_FOUND: Follow button not on profile page (logged
- BUTTON_NOT_FOUND
- TikTok returned no notifications
- Search failed: HTTP ${res.status}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/7490b282f38838e7.
Report an issue: GitHub.