{
  "id": "1rkBAEgIIY3FKh9L",
  "name": "Claude Scrapes TikTok Trends, Seedance 2.0 - udemy - vide",
  "tags": [],
  "nodes": [
    {
      "id": "fcba3359-8198-4ad7-a67d-e960906ff651",
      "name": "Webhook Cowork",
      "type": "n8n-nodes-base.webhook",
      "position": [
        768,
        128
      ],
      "parameters": {
        "path": "10ce116a-74a0-413e-b41e-ba155d48c44e",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "67861dc9-75a3-46bd-af5c-fe842d513674",
      "name": "Normalize Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        976,
        128
      ],
      "parameters": {
        "jsCode": "// The webhook can receive either a single object or an array.\n// We normalize to always work with one clean object.\nconst raw = $input.first().json;\n\n// Case 1: Postman sends array of objects with {headers, body, ...}\n// Case 2: Cowork sends body directly\nlet body;\nif (Array.isArray(raw) && raw[0] && raw[0].body) {\n  body = raw[0].body;\n} else if (raw.body && typeof raw.body === 'object') {\n  body = raw.body;\n} else {\n  body = raw;\n}\n\nif (!body.original_concepts || !Array.isArray(body.original_concepts)) {\n  throw new Error('Invalid payload: original_concepts missing');\n}\n\nreturn [{ json: body }];"
      },
      "typeVersion": 2
    },
    {
      "id": "1cc9ae81-46da-46e2-bf99-76c3817c5874",
      "name": "Save Trend to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1184,
        128
      ],
      "parameters": {
        "columns": {
          "value": {
            "niche": "={{ $json.niche }}",
            "run_date": "={{ $json.run_date }}",
            "concepts_json": "={{ JSON.stringify($json.original_concepts) }}",
            "viral_pattern_json": "={{ JSON.stringify($json.viral_pattern) }}",
            "selected_concept_id": "={{ $json.selected_concept_id }}",
            "analyzed_videos_json": "={{ JSON.stringify($json.analyzed_videos) }}"
          },
          "schema": [
            {
              "id": "run_date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "run_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "niche",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "niche",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "analyzed_videos_json",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "analyzed_videos_json",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "viral_pattern_json",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "viral_pattern_json",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "concepts_json",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "concepts_json",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "selected_concept_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "selected_concept_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1RS6jwQnyPtPbSnNlK_dQEGbDBLTvRxWEcW1Tm0cxEnw/edit#gid=0",
          "cachedResultName": "trends"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=YOUR_SHEET_ID"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "58aae2a6-bcd3-4c68-a9a2-85876ab68eca",
      "name": "Select Concept",
      "type": "n8n-nodes-base.code",
      "position": [
        1392,
        128
      ],
      "parameters": {
        "jsCode": "// Extract the selected concept from the normalized payload\nconst body = $('Normalize Payload').first().json;\nconst concepts = body.original_concepts || [];\nconst selectedId = body.selected_concept_id || 1;\nconst selected = concepts.find(c => c.concept_id === selectedId) || concepts[0];\n\nif (!selected) {\n  throw new Error('No concept found in payload');\n}\n\nreturn [{\n  json: {\n    concept_id: selected.concept_id,\n    title: selected.title,\n    hook: selected.hook,\n    storyline: selected.storyline,\n    visual_description: selected.visual_description,\n    suggested_caption: selected.suggested_caption,\n    why_viral: selected.why_viral,\n    viral_pattern: body.viral_pattern,\n    niche: body.niche,\n    run_date: body.run_date\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "55b8f60f-9b00-411d-aa12-17127fbe2d12",
      "name": "Message a model",
      "type": "@n8n/n8n-nodes-langchain.anthropic",
      "position": [
        1600,
        128
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "claude-opus-4-7",
          "cachedResultName": "claude-opus-4-7"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "==You are a cinematic prompt engineer specialized in Seedance 2.0 (ByteDance's flagship text-to-video model with native audio, physics simulation, and 1080p cinematic rendering). Your mission is to transform the creative concept below into a prompt that fully exploits Seedance 2.0's visual power.\n\nOUTPUT FORMAT: Return ONLY a valid JSON object (no markdown, no text before or after) with exactly these 3 keys:\n\n1. \"video_prompt\" \u2014 A cinematic prompt of 150-250 words in ENGLISH for Seedance 2.0 text-to-video. Follow the STRUCTURE below in exact order.\n\n2. \"tiktok_caption\" \u2014 TikTok caption in ENGLISH with scroll-stopping hook + 6 relevant hashtags. Max 180 characters total.\n\n3. \"duration_sec\" \u2014 Integer between 8 and 15. Choose based on complexity: simple scenes = 8-10s, complex evolving scenes = 12-15s.\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nVIDEO_PROMPT MANDATORY STRUCTURE (follow this exact order)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n[1] SHOT TYPE & SUBJECT (first sentence, critical)\nStart with a specific cinematic shot type + main subject. Use professional vocabulary:\n- Shot types: \"Cinematic wide shot\", \"Macro close-up\", \"Aerial establishing shot\", \"Low-angle tracking shot\", \"First-person POV\", \"Orbital drone shot\", \"Extreme close-up with shallow focus\"\n- Example: \"Cinematic first-person POV flight through dense cosmic dust clouds...\"\n\n[2] CAMERA MOVEMENT (second sentence)\nDescribe ONE continuous cinematic motion. Use directorial language:\n- \"slow dolly push-in\", \"gradual orbital pan\", \"smooth parallax tracking\", \"gentle crane lift\", \"slow reveal zoom\", \"handheld drift\", \"dramatic pullback revealing scale\"\n- Specify speed: \"extremely slow\", \"measured\", \"deliberate\"\n\n[3] VISUAL DETAILS (2-3 sentences with RICH texture vocabulary)\nDescribe what makes the scene visually rich. Use cinematographer vocabulary:\n- Textures: \"volumetric dust particles\", \"iridescent surface reflections\", \"billowing gaseous filaments\", \"crystalline ice formations\", \"weathered stone with moss patina\", \"silk fabric in slow motion\"\n- Atmosphere: \"god rays piercing through\", \"heavy atmospheric haze\", \"shimmering heat distortion\", \"floating embers\", \"thick morning fog\"\n- Physics details: \"particles drifting in zero-G\", \"water refracting light\", \"fabric responding to wind\"\n\n[4] LIGHTING (1 sentence, be specific)\nSeedance 2.0 is trained on cinematic lighting. Be technical:\n- \"dramatic chiaroscuro with hot rim light from upper-left\"\n- \"soft volumetric backlighting creating silhouettes\"\n- \"golden-hour warm sidelight with long shadows\"\n- \"cold blue key light with warm amber practical lights in background\"\n- \"high-contrast rembrandt lighting from overhead\"\n\n[5] COLOR PALETTE & MOOD (1 sentence)\nUse 3-4 specific colors + emotional tone:\n- \"Palette of deep indigo, burnt amber, and dust pink. Mood: reverent, contemplative, awe-inspiring.\"\n- \"Palette of charcoal black, crimson red, neon teal. Mood: tense, futuristic, ominous.\"\n\n[6] TECHNICAL RENDERING (final sentence, REQUIRED for cinematic quality)\nAlways end with: \"Shot on [film stock/camera], [lens], shallow depth of field, cinematic color grading, 1080p, vertical 9:16 aspect ratio, film grain, high dynamic range.\"\n- Cameras/stocks: \"ARRI Alexa\", \"RED Komodo\", \"Kodak Vision3 500T film\", \"IMAX 70mm\"\n- Lenses: \"anamorphic 35mm lens\", \"vintage Zeiss 50mm\", \"wide 24mm prime\"\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nNATIVE AUDIO (Seedance 2.0 generates audio \u2014 use it)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nAdd one final sentence describing ambient sound: \"Ambient audio: [describe \u2014 deep cinematic drone, slow orchestral swell, subtle environmental sounds like wind/water/electronic hum].\" NO dialogue, NO voiceover, NO music with lyrics.\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nSTRICT RULES (violating any = FAILED generation)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n- NO shot lists (\"Shot 1, Shot 2...\" or \"0-3s, 3-6s...\") \u2014 ONE continuous scene only\n- NO talking human faces, NO lip-sync, NO dialogue\n- NO on-screen text, NO typography, NO subtitles, NO captions (overlays added in post)\n- NO brand names, NO real public figures, NO copyrighted characters\n- NO forbidden words: \"intimate\", \"sensual\", \"pulling away\", \"touching\" (trigger content filters)\n- Keep it ONE unified continuous action \u2014 if the storyline has multiple beats, pick the MOST visually striking one\n> **Note:** For the `suggested_caption` field in each original concept, limit hashtags to a maximum of 5. TikTok's algorithm currently penalizes captions with too many hashtags \u2014 3 to 5 highly relevant hashtags outperform 10+ generic ones.\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nCONCEPT TO TRANSFORM\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nTitle: {{ $json.title }}\nHook: {{ $json.hook }}\nStoryline (inspiration only \u2014 pick the most cinematic 8-15s moment): {{ $json.storyline }}\nVisual description (inspiration for style): {{ $json.visual_description }}\nOriginal suggested caption: {{ $json.suggested_caption }}\nNiche: {{ $json.niche }}\n\nViral pattern (for caption only \u2014 NOT for video_prompt):\n{{ JSON.stringify($json.viral_pattern) }}\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nCRITICAL REMINDER\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nSeedance 2.0 is a high-end cinematic model. Vague prompts = generic output. Rich cinematographer vocabulary = stunning results. Your prompt must read like a director of photography briefing, not a description of a TikTok video. Aim for the quality of JWST imagery, Denis Villeneuve films, or Apple product commercials \u2014 that's the caliber Seedance can deliver when prompted correctly."
            }
          ]
        }
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "1b3d9a13-c7ed-4285-bbf3-01f64fdf549f",
      "name": "Parse Claude Output",
      "type": "n8n-nodes-base.code",
      "position": [
        1952,
        128
      ],
      "parameters": {
        "jsCode": "// Parse Claude's JSON response safely\nconst claudeResponse = $input.first().json;\nconst textBlock = (claudeResponse.content || []).find(c => c.type === 'text');\nif (!textBlock) throw new Error('No text block in Claude response');\n\nlet raw = textBlock.text.trim();\n// Strip potential markdown fences\nraw = raw.replace(/^```json\\s*/i, '').replace(/^```\\s*/i, '').replace(/```\\s*$/,'').trim();\n\nlet parsed;\ntry {\n  parsed = JSON.parse(raw);\n} catch (e) {\n  throw new Error('Claude did not return valid JSON: ' + raw.substring(0, 300));\n}\n\nconst concept = $('Select Concept').first().json;\n\nreturn [{\n  json: {\n    video_prompt: parsed.video_prompt,\n    tiktok_caption: parsed.tiktok_caption,\n    duration_sec: 4,\n    concept_title: concept.title,\n    concept_hook: concept.hook,\n    concept_storyline: concept.storyline\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "7dba4e49-b772-4b75-8064-fe8b819f96b2",
      "name": "Seedance - Start Generation",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2160,
        128
      ],
      "parameters": {
        "url": "https://api.atlascloud.ai/api/v1/model/generateVideo",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"model\": \"bytedance/seedance-2.0/text-to-video\",\n  \"ratio\": \"9:16\",\n  \"prompt\": {{ JSON.stringify($json.video_prompt) }},\n  \"duration\": -1,\n  \"watermark\": false,\n  \"resolution\": \"720p\",\n  \"web_search\": false,\n  \"generate_audio\": true,\n  \"return_last_frame\": false\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "9254b9cc-bff1-4bd9-becc-197c2bf1e5c3",
      "name": "Wait Before Poll",
      "type": "n8n-nodes-base.wait",
      "position": [
        1728,
        560
      ],
      "parameters": {
        "amount": 30
      },
      "typeVersion": 1.1
    },
    {
      "id": "fedebbdf-816e-41e8-856d-79b45d358c6f",
      "name": "Seedance - Poll Status",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1936,
        560
      ],
      "parameters": {
        "url": "=https://api.atlascloud.ai/api/v1/model/prediction/{{ $('Seedance - Start Generation').first().json.id ||  $('Seedance - Start Generation').first().json.data?.id }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "e8b466ec-505f-4e58-bb19-ea7f74fe33ca",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        2144,
        560
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "bd2793e4-b927-4cee-8357-5c9f5bc1cff8",
              "operator": {
                "type": "string",
                "operation": "contains"
              },
              "leftValue": "={{ $json.data.status }}",
              "rightValue": "completed"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "95b6414e-fb28-4e8f-8c96-17241da75521",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        2144,
        784
      ],
      "parameters": {
        "amount": 30
      },
      "typeVersion": 1.1
    },
    {
      "id": "6ed05ef6-3063-45e2-8767-9c42d098cdb5",
      "name": "Extract Video URL",
      "type": "n8n-nodes-base.code",
      "position": [
        2464,
        544
      ],
      "parameters": {
        "jsCode": "const r = $input.first().json;\nconst data = r.data || r;\nconst videoUrl = (data.outputs && data.outputs[0]) || data.output || data.video_url;\nif (!videoUrl) throw new Error('No video URL found in Seedance response: ' + JSON.stringify(data).substring(0, 300));\n\nconst parsed = $('Parse Claude Output').first().json;\nconst startResp = $('Seedance - Start Generation').first().json;\nconst predictionId = startResp.id || startResp.data?.id;\n\nreturn [{\n  json: {\n    video_url: videoUrl,\n    prediction_id: predictionId,\n    concept_title: parsed.concept_title,\n    concept_hook: parsed.concept_hook,\n    concept_storyline: parsed.concept_storyline,\n    video_prompt: parsed.video_prompt,\n    tiktok_caption: parsed.tiktok_caption\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "63eca278-7d1f-4f72-ab26-3646692745fa",
      "name": "Log Video to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2672,
        544
      ],
      "parameters": {
        "columns": {
          "value": {
            "hook": "={{ $json.concept_hook }}",
            "storyline": "={{ $json.concept_storyline }}",
            "timestamp": "={{ $now.toISO() }}",
            "video_url": "={{ $json.video_url }}",
            "concept_title": "={{ $json.concept_title }}",
            "visual_prompt": "={{ $json.video_prompt }}",
            "tiktok_caption": "={{ $json.tiktok_caption }}",
            "tiktok_post_status": "pending",
            "seedance_prediction_id": "={{ $('Seedance - Poll Status').item.json.data.id }}"
          },
          "schema": [
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "concept_title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "concept_title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "hook",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "hook",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "storyline",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "storyline",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "visual_prompt",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "visual_prompt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "seedance_prediction_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "seedance_prediction_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "video_url",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "video_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "tiktok_caption",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "tiktok_caption",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "tiktok_post_status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "tiktok_post_status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "tiktok_post_url",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "tiktok_post_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Instagram_post_status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Instagram_post_status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Instagram_post_url",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Instagram_post_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 989103803,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1RS6jwQnyPtPbSnNlK_dQEGbDBLTvRxWEcW1Tm0cxEnw/edit#gid=989103803",
          "cachedResultName": "productions"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=YOUR_SHEET_ID"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "90f41f60-02a8-4dae-8c55-83236dabeb85",
      "name": "Create post Tiktok",
      "type": "@blotato/n8n-nodes-blotato.blotato",
      "position": [
        2880,
        544
      ],
      "parameters": {
        "options": {},
        "platform": "tiktok",
        "accountId": {
          "__rl": true,
          "mode": "list",
          "value": "30526",
          "cachedResultUrl": "https://backend.blotato.com/v2/accounts/30526",
          "cachedResultName": "eliteshicos"
        },
        "postContentText": "={{ $json.tiktok_caption }}",
        "postContentMediaUrls": "={{ $json.video_url }}",
        "postCreateTiktokOptionIsAiGenerated": true
      },
      "credentials": {
        "blotatoApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "b8416202-eb73-4c9b-b932-305a4c22f312",
      "name": "Wait Tiktok post",
      "type": "n8n-nodes-base.wait",
      "position": [
        3088,
        544
      ],
      "parameters": {
        "unit": "minutes",
        "amount": 3
      },
      "typeVersion": 1.1
    },
    {
      "id": "6ec99212-9028-474f-a5ac-abad506029a5",
      "name": "Get post Tiktok",
      "type": "@blotato/n8n-nodes-blotato.blotato",
      "position": [
        3296,
        544
      ],
      "parameters": {
        "operation": "get",
        "postSubmissionId": "={{ $json.postSubmissionId }}"
      },
      "credentials": {
        "blotatoApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "68e043ce-ebf8-41fb-a085-312e2ca26f8f",
      "name": "Update row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3504,
        544
      ],
      "parameters": {
        "columns": {
          "value": {
            "tiktok_post_url": "={{ $json.publicUrl }}",
            "tiktok_post_status": "={{ $json.error ? 'failed' : 'published' }}",
            "seedance_prediction_id": "={{ $('Log Video to Sheets').item.json.seedance_prediction_id }}"
          },
          "schema": [
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "concept_title",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "concept_title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "hook",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "hook",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "storyline",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "storyline",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "visual_prompt",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "visual_prompt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "seedance_prediction_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "seedance_prediction_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "video_url",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "video_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "tiktok_caption",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "tiktok_caption",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "tiktok_post_status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "tiktok_post_status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "tiktok_post_url",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "tiktok_post_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Instagram_post_status",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Instagram_post_status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Instagram_post_url",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Instagram_post_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "seedance_prediction_id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 989103803,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1RS6jwQnyPtPbSnNlK_dQEGbDBLTvRxWEcW1Tm0cxEnw/edit#gid=989103803",
          "cachedResultName": "productions"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=YOUR_SHEET_ID"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "009e76b0-9522-48d9-a846-311113dd3e20",
      "name": "Update row in sheet1",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3504,
        736
      ],
      "parameters": {
        "columns": {
          "value": {
            "Instagram_post_url": "={{ $json.publicUrl }}",
            "Instagram_post_status": "={{ $json.error ? 'failed' : 'published' }}",
            "seedance_prediction_id": "={{ $('Log Video to Sheets').item.json.seedance_prediction_id }}"
          },
          "schema": [
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "concept_title",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "concept_title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "hook",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "hook",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "storyline",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "storyline",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "visual_prompt",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "visual_prompt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "seedance_prediction_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "seedance_prediction_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "video_url",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "video_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "tiktok_caption",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "tiktok_caption",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "tiktok_post_status",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "tiktok_post_status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "tiktok_post_url",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "tiktok_post_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Instagram_post_status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Instagram_post_status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Instagram_post_url",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Instagram_post_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "seedance_prediction_id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 989103803,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1RS6jwQnyPtPbSnNlK_dQEGbDBLTvRxWEcW1Tm0cxEnw/edit#gid=989103803",
          "cachedResultName": "productions"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=YOUR_SHEET_ID"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "04818fe7-5f69-42b4-88ee-745d3ec294c0",
      "name": "Create post Instagram",
      "type": "@blotato/n8n-nodes-blotato.blotato",
      "position": [
        2880,
        736
      ],
      "parameters": {
        "options": {},
        "accountId": {
          "__rl": true,
          "mode": "list",
          "value": "1687",
          "cachedResultUrl": "https://backend.blotato.com/v2/accounts/1687",
          "cachedResultName": "acces.a.vie"
        },
        "postContentText": "={{ $json.tiktok_caption }}",
        "postContentMediaUrls": "={{ $json.video_url }}"
      },
      "credentials": {
        "blotatoApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "92c0d5f8-298c-4c81-8817-f0ff55243cd5",
      "name": "Wait  Instagram post",
      "type": "n8n-nodes-base.wait",
      "position": [
        3088,
        736
      ],
      "parameters": {
        "unit": "minutes",
        "amount": 3
      },
      "typeVersion": 1.1
    },
    {
      "id": "f8fa483b-a8c4-4fb7-b21d-775b424ae4ec",
      "name": "Get post Instagram",
      "type": "@blotato/n8n-nodes-blotato.blotato",
      "position": [
        3296,
        736
      ],
      "parameters": {
        "operation": "get",
        "postSubmissionId": "={{ $json.postSubmissionId }}"
      },
      "credentials": {
        "blotatoApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "2d6ae736-372f-46c6-9e57-7acbb265b90d",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "width": 704,
        "height": 1168,
        "content": "# TikTok Viral Trend Detector \u2192 AI Video Generator \u2192 Auto-Publish \n\n## Resources\n- Video Tutorial: https://youtu.be/Bzu00hlo1AI\n- Copy Google Sheets Template: https://docs.google.com/spreadsheets/d/1RS6jwQnyPtPbSnNlK_dQEGbDBLTvRxWEcW1Tm0cxEnw/copy\n- Full Documentation: https://automatisation.notion.site/Claude-Cowork-n8n-Trend-Detector-3483d6550fd980609c96c2771088f601?source=copy_link\n\n## Use Case\nThis workflow is built for **content creators, social media managers, and automation enthusiasts** who want to automate the entire TikTok content pipeline \u2014 from trend research to video generation to publishing \u2014 without filming anything.\n\nIt's especially powerful for anyone running **faceless content channels** on TikTok and Instagram, or agencies managing multiple accounts who need to produce trend-driven content at scale with zero manual effort.\n\n&gt; \u26a0\ufe0f **Disclaimer:** This workflow uses Community Nodes (Blotato). These are only available on self-hosted n8n instances.\n\n## Setup\n**Required accounts:**\n- A **Claude.ai Pro** account with Claude Cowork enabled (for Part 1 \u2014 trend scraping and analysis)\n- An **[Apify](https://www.apify.com/?fpr=udemy)** account to run the TikTok scraper actor (`clockworks/tiktok-scraper`). Apify handles the TikTok data extraction \u2014 without it, the Cowork agent cannot retrieve viral videos.\n\n**Credentials to configure in n8n:**\n\n1. **Google Sheets OAuth2** **[Copy my template](https://docs.google.com/spreadsheets/d/1RS6jwQnyPtPbSnNlK_dQEGbDBLTvRxWEcW1Tm0cxEnw/copy)**\n\n\n2. **Anthropic API Key**\n   - Type: Anthropic credentials (built-in n8n node)\n   - Get it at: [console.anthropic.com](https://console.anthropic.com)\n   - Used for: Claude node \u2014 generating the Seedance video prompt and TikTok caption\n\n3. **Atlas Cloud API Key**\n   - Type: Header Auth (`Authorization: Bearer`)\n   - Get it at: **[AtlasCloud](https://www.atlascloud.ai?ref=8QKPJE)**\n   - Used for: Seedance 2.0 text-to-video generation (HTTP Request node)\n\n4. **Blotato API Key**\n   - Type: Blotato credentials (community node)\n   - Get it at: **[Blotato](https://blotato.com/?ref=firas)**\n   - Used for: Publishing to TikTok and Instagram"
      },
      "typeVersion": 1
    },
    {
      "id": "67fae2e7-75e1-44ff-b204-f8a33ba492f6",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        736,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 3056,
        "height": 416,
        "content": "## Step 1 -  Trend Intelligence & AI Video Prompt\nReceives the TikTok trend analysis from Claude Cowork, saves it to Google Sheets, extracts the best concept, and uses Claude to generate an optimized Seedance video prompt."
      },
      "typeVersion": 1
    },
    {
      "id": "bcf9fff8-0471-4690-a8d4-e1151b9a9b21",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        736,
        432
      ],
      "parameters": {
        "color": 7,
        "width": 1638,
        "height": 736,
        "content": "## Step 2 - AI Video Generation with Seedance 2.0\nSubmits the prompt to AtlasCloud's Seedance 2.0 model and polls every 5 seconds until the video is fully generated and ready for publishing."
      },
      "typeVersion": 1
    },
    {
      "id": "71ff8cce-0aa9-4cb6-b6c1-015350118baa",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2400,
        432
      ],
      "parameters": {
        "color": 7,
        "width": 1392,
        "height": 736,
        "content": "## Step 3 - Multi-Platform Publishing & Tracking\nPublishes the generated video simultaneously to TikTok and Instagram via Blotato, then updates Google Sheets with the post status and public URLs for both platforms."
      },
      "typeVersion": 1
    },
    {
      "id": "c5a773ff-015e-4bd7-b65a-c76269ef7a10",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        768,
        560
      ],
      "parameters": {
        "color": 2,
        "width": 832,
        "height": 560,
        "content": "# \ud83c\udfa5 Tutorial :\n@[youtube](Bzu00hlo1AI) "
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "00622505-6043-43ac-bea6-c79071fad1bd",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Extract Video URL",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait": {
      "main": [
        [
          {
            "node": "Seedance - Poll Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Select Concept": {
      "main": [
        [
          {
            "node": "Message a model",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Cowork": {
      "main": [
        [
          {
            "node": "Normalize Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get post Tiktok": {
      "main": [
        [
          {
            "node": "Update row in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Message a model": {
      "main": [
        [
          {
            "node": "Parse Claude Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait Before Poll": {
      "main": [
        [
          {
            "node": "Seedance - Poll Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait Tiktok post": {
      "main": [
        [
          {
            "node": "Get post Tiktok",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Video URL": {
      "main": [
        [
          {
            "node": "Log Video to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Payload": {
      "main": [
        [
          {
            "node": "Save Trend to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create post Tiktok": {
      "main": [
        [
          {
            "node": "Wait Tiktok post",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get post Instagram": {
      "main": [
        [
          {
            "node": "Update row in sheet1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Video to Sheets": {
      "main": [
        [
          {
            "node": "Create post Tiktok",
            "type": "main",
            "index": 0
          },
          {
            "node": "Create post Instagram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Claude Output": {
      "main": [
        [
          {
            "node": "Seedance - Start Generation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Trend to Sheets": {
      "main": [
        [
          {
            "node": "Select Concept",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait  Instagram post": {
      "main": [
        [
          {
            "node": "Get post Instagram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create post Instagram": {
      "main": [
        [
          {
            "node": "Wait  Instagram post",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Seedance - Poll Status": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Seedance - Start Generation": {
      "main": [
        [
          {
            "node": "Wait Before Poll",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}