All notable changes to this Actor will be documented here.
[1.2] — 2026-05-22
Removed
account mode — TikTok stopped shipping user video lists in public HTML
in 2026 and the lazy-loaded XHR endpoint requires JS-generated signatures
(X-Bogus, _signature) that cannot be reproduced server-side. Keeping a
broken mode in the UI was hurting the actor more than it helped. Existing
users who still pass mode: "account" get a clear deprecation warning and
the actor falls back to URL mode if any URLs are also provided.
username and accountLimit input fields removed from the schema.
Added
recommendations[] — every video result now includes a list of
actionable, plain-English advice based on the detected signals. Examples:
🚨 TikTok officially removed this video. You will need to re-upload...
💬 Comments are disabled. Re-enable them in the … menu...
📉 Engagement rate 0.4% is well below average for 50,000 views — possible soft suppression...
⏱️ Sub-7-second video. Average watch time is currently the strongest FYP signal...
Recommendations are tier-prefixed by health (✅ healthy / 🟡 slightly /
🟠 restricted / 🔴 heavy / ⛔ shadowbanned), so the first item is always the
bottom-line verdict.
Toggle via new boolean input includeRecommendations (default true).
urlText — paste-friendly textarea input that accepts URLs separated by
newlines, commas or any whitespace. Useful when copying a list out of a
spreadsheet or doc. Merged with the existing urls array; duplicates are
removed automatically.
Empty-input safety net upgraded — the actor now logs a clear error and
exits FAILED instead of running through retries on no work.
Migration
If you only used URL mode, no changes needed. The new recommendations[]
field appears on every record.
If you used account mode, switch to passing direct video URLs. The Python
SDK's check_one() and check_urls() already do this and return all 30+
shadow-ban signals.
[1.1.5] — 2026-05-22
Known broken — account mode
Confirmed today via live tests on multiple usernames (@tiktok, @catstory073):
TikTok stopped shipping user-page video lists in public HTML some time in 2026.
Pages now serve userInfo only, with videos lazy-loaded via signed XHR
(/api/post/item_list/ requires X-Bogus + _signature JS-generated tokens).
Cannot be reached without a JavaScript runtime. Headless browser would change
unit cost from $0.01 → $0.05+ which kills the actor's economics.
What changed:
Account mode now fails with an explicit, actionable error instead of a vague
"All user-page strategies failed" loop. The error log includes the workaround
(switch to urls mode + direct video links).
Recursive parser + bare-id fallback added in 1.1.4 are kept — they catch any
future TikTok layout that resumes shipping the list, no code change needed.
URL mode (mode: urls) and the entire signal-detection pipeline are unaffected.
[1.1.4] — 2026-05-22
Fixed — account mode now survives TikTok layout changes
Account mode was returning All user-page strategies failed even when TikTok served full 350 KB pages because the parser only knew two specific JSON keys for the video list. TikTok routinely moves these between releases.
Recursive parser: walks the entire embedded JSON tree (UNIVERSAL_DATA, SIGI_STATE, NEXT_DATA, plus any <script type="application/json"> blob) and detects video lists structurally — by content shape, not by key name. Survives future schema renames.
Bare-ID fallback: when JSON contains zero video lists (TikTok now sometimes ships only userInfo and lazy-loads videos client-side), the actor extracts /video/<id> paths from raw HTML and fetches each video page individually. Slower (N requests instead of 1) but reliable.
Better error message: All user-page strategies failed now also reports which strategy returned the largest HTML so we can diagnose layout issues from logs alone.
[1.1.3] — 2026-05-22
Fixed — better error messages on missing input
Account mode without username previously exited with status code 1 and no log line, leaving users staring at a silent fail. Now logs an explicit error, pushes a record into the dataset and sets a clear status message: "Account mode requires a 'TikTok username' (without @). Set the 'username' input field, or switch Mode to 'urls'..."
URLs mode without urls gets the same treatment (clear log + dataset record).
Unknown mode value now logs the actual value that was passed plus the two valid options.
[1.1.2] — 2026-05-22
Fixed — shadow ban detection now actually works
TikTok exposes indexEnabled (the primary shadow ban flag) ONLY on mobile-UA pages. Desktop pages omit it entirely. Strategy order rewritten to put mobile UA FIRST so the shadow ban signal is captured in a single request.
Parser now keeps fetching past partial matches if a richer payload (with indexEnabled) is still possible — desktop hits become a fallback rather than a premature success.
Embed endpoints moved to last position because they don't expose shadow ban data at all.
Added
Multi-signal detection beyond indexEnabled: takeDown, secret, privateItem, forFriend, isReviewing, warnInfo, shareEnabled, duetDisplay, stitchDisplay, itemCommentStatus, downloadSetting, plus author-level secret/privateAccount. Composite verdict triggers shadowbanned=true on any hard signal or 3+ soft restrictions.
[1.1.1] — 2026-05-22
Fixed
Replaced removed httpx proxies= argument with AsyncClient(proxy=...) — fixes runtime error on Apify SDK 3.4 / httpx 0.28.
compute_viral_potential and createDate now coerce createTime to int before passing to datetime.fromtimestamp — fixes 'str' object cannot be interpreted as an integer on TikTok responses where the field is stringified.
Added — Anti-WAF resilience
Multi-strategy fetcher: embed/v2 → embed → desktop UA → mobile UA → m.tiktok.com mirror → Googlebot UA before failing.
Parser now also reads the new webapp.reflow.video.detail scope used on mobile pages.
oEmbed metadata fallback: when full HTML is blocked, the actor now still returns title, author, thumbnail and partial=true instead of an empty error record.
_extract_video_id_from_url helper for robust ID parsing across URL forms.
proxyCountry input (default US) — pin residential proxy to a country to stop region-redirects (e.g. /in/about) that previously broke parsing.
customProxyUrls input — supply your own proxies in host:port:user:pass, user:pass@host:port, or full URL formats. Round-robin rotation. Overrides Apify proxy when set.
[1.1] — 2026-05-22
Added — Major intelligence expansion
New shadow ban signals (beyond just indexEnabled):
forYouEligible — whether video is eligible for For You Page
searchVisible — whether video appears in search results
divertedToPrivate — TikTok forced the video to private (strong ban signal)
duetDisabled — duet feature disabled
stitchDisabled — stitch feature disabled
commentDisabled — comments disabled
downloadDisabled — downloads disabled
privateAccount — account is private
isAd — video is an ad
banReasonHints[] — human-readable list of detected restrictions
restrictionCount — total number of active restrictions
New computed metrics:
videoHealthScore (0-100) — composite signal from all ban indicators + engagement