Zie619/n8n-workflows · error · Error
Could not find video URL in the JSON data.
Error message
Could not find video URL in the JSON data.
What it means
Thrown by the same 'Scrape raw video URL' node after it successfully found and parsed the __UNIVERSAL_DATA_FOR_REHYDRATION__ JSON blob in the TikTok page HTML. The parsed data is walked down __DEFAULT_SCOPE__ → 'webapp.video-detail' → itemInfo → itemStruct → video → playAddr; if that deep path yields nothing, the node refuses to continue.
Source
Thrown at workflows/Code/1802_Code_Manual_Import_Webhook.json:76
"name": "User-Agent",
"value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/91.0.4472.124"
}
]
}
},
"typeVersion": 4.2,
"notes": "This httpRequest node performs automated tasks as part of the workflow."
},
{
"id": "734a5304-f67f-4ace-a1da-0d268664452c",
"name": "Scrape raw video URL",
"type": "n8n-nodes-base.code",
"position": [
480,
20
],
"parameters": {
"jsCode": "const html = $input.first().json.data;\nconst headers = $input.first().json.headers || {};\nconst cookies = headers['set-cookie'] || [];\n\nif (!html) {\n throw new Error(\"HTML body is undefined. Check the previous node's output.\");\n}\nconst regex = /<script id=\"__UNIVERSAL_DATA_FOR_REHYDRATION__\" type=\"application\\/json\">([\\s\\S]*?)<\\/script>/;\nconst match = html.match(regex);\n\nif (match) {\n const jsonStr = match[1];\n const data = JSON.parse(jsonStr);\n const videoUrl = data?.__DEFAULT_SCOPE__?.[\"webapp.video-detail\"]?.itemInfo?.itemStruct?.video?.playAddr;\n if (!videoUrl) {\n throw new Error(\"Could not find video URL in the JSON data.\");\n }\n return [{ json: { videoUrl, cookies: cookies.join('; ') } }];\n} else {\n throw new Error(\"Could not find __UNIVERSAL_DATA_FOR_REHYDRATION__ script in the HTML.\");\n}"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "f574ccb8-6f5f-4e55-a2d5-7ad775d3c4e5",
"name": "Output video file without watermark",
"type": "n8n-nodes-base.httpRequest",
"position": [
900,
20
],
"parameters": {
"url": "{{ $env.BASE_URL }}",
"options": {
"response": {
"response": {
"responseFormat": "file"View on GitHub (pinned to 94007c1445)
Solutions
- Verify the submitted video URL opens publicly in an incognito browser (not private, not deleted, not region-locked).
- Log Object.keys(data.__DEFAULT_SCOPE__) and the shape under 'webapp.video-detail' to see which hop broke — itemInfo may contain an error status instead of itemStruct.
- Add browser-like headers (User-Agent, Referer) and cookies to the upstream fetch to avoid bot-check pages.
- If TikTok renamed the field, update the optional-chaining path to the new key; consider falling back to the itemStruct.video.downloadAddr or bitrateInfo playAddr variants.
Example fix
// before
const videoUrl = data?.__DEFAULT_SCOPE__?.["webapp.video-detail"]?.itemInfo?.itemStruct?.video?.playAddr;
if (!videoUrl) {
throw new Error("Could not find video URL in the JSON data.");
}
// after
const detail = data?.__DEFAULT_SCOPE__?.["webapp.video-detail"];
const item = detail?.itemInfo?.itemStruct;
const videoUrl = item?.video?.playAddr
|| item?.video?.bitrateInfo?.[0]?.PlayAddr?.UrlList?.[0]
|| item?.video?.downloadAddr;
if (!videoUrl) {
throw new Error(`Could not find video URL. itemInfo status: ${JSON.stringify(detail?.itemInfo?.itemWriteType ?? detail?.itemInfo)}`);
} Defensive patterns
Strategy: type-guard
Validate before calling
const detail = data?.__DEFAULT_SCOPE__?.["webapp.video-detail"]; const item = detail?.itemInfo?.itemStruct; const videoUrl = item?.video?.playAddr || item?.video?.bitrateInfo?.[0]?.PlayAddr?.UrlList?.[0];
Type guard
function extractPlayAddr(d) {
const v = d?.__DEFAULT_SCOPE__?.['webapp.video-detail']?.itemInfo?.itemStruct?.video;
return v?.playAddr || v?.downloadAddr || v?.bitrateInfo?.[0]?.PlayAddr?.UrlList?.[0] || null;
} Prevention
- Validate the video URL is public (not private/deleted/region-locked) before submitting.
- Try multiple playAddr variants — TikTok exposes several URL fields.
- Include the itemInfo status in error output to distinguish bot-checks from removed videos.
- Expect TikTok DOM/JSON drift; centralize the extraction path so fixes touch one function.
When it happens
Trigger: The TikTok page embedded valid hydration JSON but the video-detail scope is absent or shaped differently: the video is private, deleted, region-blocked, age-restricted, a photo post instead of a video, or TikTok served a login/bot-check page whose hydration blob has no webapp.video-detail key. It also fires when playAddr was renamed in a TikTok frontend update.
Common situations: Users submitting URLs to private/removed videos; TikTok A/B tests or frontend changes renaming playAddr; scraping from a datacenter IP triggering bot interstitials; the item being a slideshow (image post) with no video object.
Related errors
- HTML body is undefined. Check the previous node's output.
- Could not find __UNIVERSAL_DATA_FOR_REHYDRATION__ script in
- Approved quantity must be greater than 0
- ${fileName} → ${baseName} → Unrecognized file name structure
- The video ID parameter is empty.
AI-assisted analysis of Zie619/n8n-workflows@94007c1445 (2026-08-15).
Data as JSON: /api/errors/afbe3c04b37bc63f.
Report an issue: GitHub.