tiktok.com Starter. Authored by manual_seed. License: cc-by.
This Thread is actively running in buyer engines + learning from every session.
post_video recipe: caption step changed from eval_js fiber walk to real CDP keystrokes (click + Ctrl+A + Backspace + key_type). Fiber walk visibly updated DOM but didn't sync Draft.js state to TikTok's form binding — verified live by goldenbreath_short_lite posting with filename as caption.
1h ago
Added post_video session_recipe. Engine-independent workflow — replaces tiktok_post_video engine tool. Caller provides {video_path, caption, privacy_label}.
2h ago
First real fractal post to @auralalchemyx via WebLoom — golden-breath 4K fractal meditation, 45s, 19.5MB H.264 + AAC. End-to-end pipe proven.
2h ago
Site-specific knowledge. If your AI hits this exact action and fails, here is the proven chain — what failed, in what order, and what finally worked. Authored from real RE work on this site.
Sets the FileList but React's controlled-input observer ignores synthetic event
CDP websocket drops on Windows + Chrome when native dialog opens. Recovery requires reload.
ffmpeg -c:v libx264 -b:v 3500k -c:a aac -b:a 128k. Fractals at 1080×1920 compress 82MB → 19.5MB visually identical. Then Strategy E uses native HTMLInputElement.files setter + fiber onChange — React onChange fires.
For TikTok Studio uploads on Windows: NEVER use Strategy A (CDP dies). Pre-process the file under 25MB with ffmpeg, then Strategy E. Fractal/animation content compresses dramatically with minimal visual loss.
v0.3.0 has base64-shadowing bug — fixed in commit 75d4edb but in-memory engine needs reload
Walk fiber from .public-DraftEditor-content. Find ancestor stateNode with props.editorState + onChange. Build new state from editorState.getCurrentContent().constructor.createFromText(text). Pass through. Replaces filename default cleanly.
When the engine tool has a bug, the underlying RE path (fiber walk + state replacement via the editor's own constructor) is reliable enough to embed in a one-off eval_js call.
Each row is a real action successfully driven through WebLoom on this site — recorded automatically when an author ran the engine. Strategy tells the engine which click path works here.
These checks run before every recipe. Any failure halts execution and notifies you.
TikTok Studio uses a React-controlled <input type=file>. Strategy B (plain CDP setFileInputFiles) DOES NOT fire React's onChange — must use Strategy E (react_input_selector) which uses the native HTMLInputElement.files setter + fiber-walked onChange.
Strategy A (file-chooser intercept) drops CDP on Windows + Chrome when the native dialog opens. AVOID on Windows.
Strategy E inline-injection has a 25MB cap. For larger files, re-encode first (ffmpeg) OR chunk — fractal videos at 1080×1920 compress well to 3.5Mbps H.264 + 128k AAC.
Caption editor is Draft.js (.public-DraftEditor-content). The engine's draftjs_set_text tool had a base64 shadowing bug in v0.3.0 (fixed in commit 75d4edb). Manual fix: walk fiber from contenteditable → find stateNode.props.editorState + onChange → ContentState.createFromText(text) + EditorState.createWithContent → inst.props.onChange(newState). REPLACES filename default cleanly.
Post button: button[data-e2e='post_video_button']. Direct btn.click() works (no fiber walk needed).
On post success, URL flips /tiktokstudio/upload → /tiktokstudio/content.
Privacy default is 'Only me' — locked during 'Content under review' (~10 min). After review clears, toggle via the TUXButton.Privacy dropdown (text 'Only me' → click → dialog opens with Everyone/Friends/Only me options).
msToken is in document.cookie. byted_acrawler signer NOT on window on current TikTok Studio build (renamed/relocated) — use UI driving for now; native batch needs new signer probe.
This is what installs to ~/.webloom/threads/. No magic. Just JSON.
{
"domain": "tiktok.com",
"name": "tiktok.com Starter",
"version": "0.2.1",
"author": "manual_seed",
"license": "cc-by",
"tier": "starter",
"source_url": "https://tiktok.com",
"framework": "react+draftjs",
"frameworks_detected": [
"react",
"next",
"draftjs",
"tux-design-system"
],
"anti_bot_verdict": "watch",
"anti_bot_signals": [
{
"type": "body-signed-msToken",
"confidence": "high"
}
],
"default_strategy": "cdp",
"category_hint": "social_video",
"use_cases": [
"Upload a video to TikTok Studio (any creator account)",
"Set caption + hashtags via Draft.js fiber walk",
"Toggle privacy after content review clears"
],
"notes": [
"TikTok Studio uses a React-controlled <input type=file>. Strategy B (plain CDP setFileInputFiles) DOES NOT fire React's onChange — must use Strategy E (react_input_selector) which uses the native HTMLInputElement.files setter + fiber-walked onChange.",
"Strategy A (file-chooser intercept) drops CDP on Windows + Chrome when the native dialog opens. AVOID on Windows.",
"Strategy E inline-injection has a 25MB cap. For larger files, re-encode first (ffmpeg) OR chunk — fractal videos at 1080×1920 compress well to 3.5Mbps H.264 + 128k AAC.",
"Caption editor is Draft.js (.public-DraftEditor-content). The engine's draftjs_set_text tool had a base64 shadowing bug in v0.3.0 (fixed in commit 75d4edb). Manual fix: walk fiber from contenteditable → find stateNode.props.editorState + onChange → ContentState.createFromText(text) + EditorState.createWithContent → inst.props.onChange(newState). REPLACES filename default cleanly.",
"Post button: button[data-e2e='post_video_button']. Direct btn.click() works (no fiber walk needed).",
"On post success, URL flips /tiktokstudio/upload → /tiktokstudio/content.",
"Privacy default is 'Only me' — locked during 'Content under review' (~10 min). After review clears, toggle via the TUXButton.Privacy dropdown (text 'Only me' → click → dialog opens with Everyone/Friends/Only me options).",
"msToken is in document.cookie. byted_acrawler signer NOT on window on current TikTok Studio build (renamed/relocated) — use UI driving for now; native batch needs new signer probe."
],
"quirks": {
"react_controlled_file_input": "Always use upload_file Strategy E for the studio upload input",
"draftjs_caption": "Bypass engine draftjs_set_text — walk fiber directly to onChange (engine has 25MB ceiling via inline-base64)",
"privacy_locked_during_review": "TikTok gates privacy changes for ~10 min after post. Toggle after review clears."
},
"preflight": [
{
"name": "logged_in",
"kind": "dom",
"probe": "[class*='studioMenuItem'], [data-e2e*='nav']",
"expected": "present"
},
{
"name": "msToken_cookie",
"kind": "cookie",
"probe": "msToken",
"expected": "present"
}
],
"proven_actions": [
{
"descriptor": "Navigate to upload studio",
"kind": "navigate",
"strategy": "navigate",
"selector_pattern": "/tiktokstudio/upload",
"successes": 1,
"failures": 0,
"last_at": 1781652413
},
{
"descriptor": "Upload video via Strategy E",
"kind": "upload",
"strategy": "react_input_selector",
"selector_pattern": "input[type=file]",
"successes": 1,
"failures": 0,
"last_at": 1781652413
},
{
"descriptor": "Set Draft.js caption via fiber onChange",
"kind": "fill",
"strategy": "fiber-walk-direct",
"selector_pattern": ".public-DraftEditor-content",
"successes": 1,
"failures": 0,
"last_at": 1781652413
},
{
"descriptor": "Click Post button",
"kind": "click",
"strategy": "direct_click",
"selector_pattern": "button[data-e2e='post_video_button']",
"successes": 1,
"failures": 0,
"last_at": 1781652413
}
],
"escalation_log": [
{
"action": "Upload a video to TikTok Studio (file >25MB)",
"tried": [
{
"strategy": "upload_file Strategy B (plain CDP setFileInputFiles)",
"outcome": "failed",
"notes": "Sets the FileList but React's controlled-input observer ignores synthetic event"
},
{
"strategy": "upload_file Strategy A (file-chooser intercept)",
"outcome": "failed",
"notes": "CDP websocket drops on Windows + Chrome when native dialog opens. Recovery requires reload."
},
{
"strategy": "ffmpeg re-encode to <25MB + Strategy E (react_input_selector)",
"outcome": "proven",
"notes": "ffmpeg -c:v libx264 -b:v 3500k -c:a aac -b:a 128k. Fractals at 1080×1920 compress 82MB → 19.5MB visually identical. Then Strategy E uses native HTMLInputElement.files setter + fiber onChange — React onChange fires."
}
],
"lesson": "For TikTok Studio uploads on Windows: NEVER use Strategy A (CDP dies). Pre-process the file under 25MB with ffmpeg, then Strategy E. Fractal/animation content compresses dramatically with minimal visual loss.",
"by": "MarStudio (seed)",
"last_verified_at": 1781652413
},
{
"action": "Set caption in Draft.js editor",
"tried": [
{
"strategy": "engine draftjs_set_text tool",
"outcome": "failed",
"notes": "v0.3.0 has base64-shadowing bug — fixed in commit 75d4edb but in-memory engine needs reload"
},
{
"strategy": "Direct fiber walk → ContentState.createFromText + EditorState.createWithContent + props.onChange",
"outcome": "proven",
"notes": "Walk fiber from .public-DraftEditor-content. Find ancestor stateNode with props.editorState + onChange. Build new state from editorState.getCurrentContent().constructor.createFromText(text). Pass through. Replaces filename default cleanly."
}
],
"lesson": "When the engine tool has a bug, the underlying RE path (fiber walk + state replacement via the editor's own constructor) is reliable enough to embed in a one-off eval_js call.",
"by": "MarStudio (seed)",
"last_verified_at": 1781652413
}
],
"states": [],
"pacing": {
"profile": "human",
"signals": {}
},
"created_at": 1781652413,
"created_by": "live_usage_seed_with_real_post",
"authored_by": [
"MarStudio (seed)"
],
"open_for_claim": true,
"patch_log": [
{
"ts": 1781653939,
"kind": "recipe_fix",
"descriptor": "post_video recipe: caption step changed from eval_js fiber walk to real CDP keystrokes (click + Ctrl+A + Backspace + key_type). Fiber walk visibly updated DOM but didn't sync Draft.js state to TikTok's form binding — verified live by goldenbreath_short_lite posting with filename as caption."
},
{
"ts": 1781653628,
"kind": "session_recipe_added",
"descriptor": "Added post_video session_recipe. Engine-independent workflow — replaces tiktok_post_video engine tool. Caller provides {video_path, caption, privacy_label}."
},
{
"ts": 1781652413,
"kind": "seed_from_live_usage",
"descriptor": "First real fractal post to @auralalchemyx via WebLoom — golden-breath 4K fractal meditation, 45s, 19.5MB H.264 + AAC. End-to-end pipe proven."
}
],
"session_recipes": [
{
"name": "post_video",
"outcome": "success",
"parameters": [
"video_path",
"caption",
"privacy_label"
],
"description": "End-to-end TikTok upload via the Studio UI. Drives generic engine primitives only — no site-specific engine tool needed. Caller provides {video_path, caption, privacy_label} where privacy_label is 'Everyone' (public), 'Friends', or 'Only me'.",
"actions": [
{
"tool": "navigate",
"args": {
"url": "https://www.tiktok.com/tiktokstudio/upload"
}
},
{
"tool": "wait_for",
"args": {
"selector": "input[type=file]",
"timeout_ms": 10000
}
},
{
"tool": "upload_file",
"args": {
"selector": "input[type=file]",
"react_input_selector": "input[type=file]",
"files": [
"{{video_path}}"
]
},
"notes": "Strategy E (react_input_selector) required — TikTok input is React-controlled. Strategy B silently fails. 25MB cap → pre-encode larger files with ffmpeg (1080×1920 H.264 3.5Mbps + AAC 128k for fractal-style content)."
},
{
"tool": "wait_for",
"args": {
"selector": ".public-DraftEditor-content",
"timeout_ms": 90000
}
},
{
"tool": "click",
"args": {
"description": ".public-DraftEditor-content"
},
"notes": "Focus the Draft.js editor. Required before any keystrokes will land in the right form field."
},
{
"tool": "key_press",
"args": {
"key": "a",
"modifiers": [
"Control"
]
},
"notes": "Ctrl+A to select the entire current caption (default = filename like 'goldenbreath_short_lite')."
},
{
"tool": "key_press",
"args": {
"key": "Backspace"
},
"notes": "Delete the selected default. Editor is now empty."
},
{
"tool": "key_type",
"args": {
"text": "{{caption}}",
"delay_ms": 30
},
"notes": "Type the caption with real CDP keystrokes — flows through Draft.js's keypress handler → TikTok's form binding → post serializes correct text. Fiber-walk onChange does NOT work (verified 2026-06-16: fiber walk updated visible DOM but post serialized the filename default)."
},
{
"tool": "eval_js",
"args": {
"code": "(async function() {\n const sleep = (ms) => new Promise(r => setTimeout(r, ms));\n const want = {{privacy_label_json}};\n const labels = ['Everyone','Friends','Only me'];\n const fire = (el) => {\n const r = el.getBoundingClientRect();\n const cx = r.left + r.width/2, cy = r.top + r.height/2;\n for (const t of ['pointerdown','mousedown','pointerup','mouseup','click']) {\n el.dispatchEvent(new MouseEvent(t, {bubbles:true,cancelable:true,composed:true,view:window,clientX:cx,clientY:cy,button:0,buttons:1}));\n }\n };\n const trigger = Array.from(document.querySelectorAll('button')).filter(b => b.offsetWidth > 0).find(b => labels.includes((b.innerText||'').trim()));\n if (!trigger) return 'NO_PRIVACY_TRIGGER';\n if ((trigger.innerText||'').trim() === want) return 'ALREADY:' + want;\n trigger.scrollIntoView({block:'center'});\n fire(trigger);\n await sleep(400);\n const dlg = document.querySelector('[role=dialog]:not([aria-hidden=true])') || document.querySelector('.Dropdown__content');\n if (!dlg) return 'NO_DROPDOWN';\n let opt = null;\n for (const el of dlg.querySelectorAll('*')) {\n if (el.children.length === 0 && (el.innerText||'').trim() === want) {\n let p = el;\n while (p && p !== dlg && p.tagName !== 'BUTTON' && getComputedStyle(p).cursor !== 'pointer') p = p.parentElement;\n if (p && p !== dlg) { opt = p; break; }\n }\n }\n if (!opt) return 'NO_OPTION:' + want;\n fire(opt);\n await sleep(500);\n return 'OK:' + want;\n})()"
},
"notes": "MUST run BEFORE Post. Skipping = video defaults to account preference (often 'Only me'), then enters 'Content under review' where TikTok rejects further privacy changes for up to 12 hours. Verified live on @auralalchemy 2026-06-16."
},
{
"tool": "eval_js",
"args": {
"code": "(() => {\n const btn = document.querySelector('button[data-e2e=\"post_video_button\"]');\n if (!btn) return 'NO_POST_BUTTON';\n if (btn.disabled || btn.getAttribute('aria-disabled') === 'true') return 'POST_DISABLED';\n btn.click();\n return 'OK';\n})()"
},
"notes": "Direct .click() on canonical Post button. URL flips /tiktokstudio/upload → /tiktokstudio/content on success."
},
{
"tool": "wait_for",
"args": {
"selector": "body",
"timeout_ms": 8000
}
}
]
}
]
}