AutomationFlowsSocial Media › Extract Tiktok Reaction Hooks with Renderio Scene Detection

Extract Tiktok Reaction Hooks with Renderio Scene Detection

ByRenderIO @hodho on n8n.io

Works on both n8n Cloud and self-hosted instances. This template uses the community node, which is installable on n8n Cloud and self-hosted setups.

Event trigger★★★★☆ complexity19 nodesForm TriggerN8N Nodes RenderioHTTP RequestForm
Social Media Trigger: Event Nodes: 19 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #15883 — we link there as the canonical source.

This workflow follows the Form → Form Trigger recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "hvMPKiLrtGneutkK",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "TikTok Visual Hook Splitter",
  "tags": [],
  "nodes": [
    {
      "id": "7197cd90-2517-4b06-a69d-9f451e04738e",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -416,
        -240
      ],
      "parameters": {
        "width": 480,
        "height": 848,
        "content": "## TikTok Visual Hook Splitter\n\n### How it works\n\n1. Listens for a TikTok URL submission and triggers the workflow.\n2. Downloads the video and initiates scene detection via Renderio.\n3. Waits for the detection process, checks the status, and handles retries if needed.\n4. Parses the detected scenes and splits the video using an HTTP request.\n5. Monitors the split process, handles retries, and displays the download link when completed.\n\n### Setup steps\n\n- [ ] Configure formTrigger for TikTok URL submission.\n- [ ] Ensure Renderio API is accessible and configured.\n- [ ] Set HTTP request parameters for video splitting.\n\n### Customization\n\nThe wait times and retry logic can be customized for preferred duration and conditions."
      },
      "typeVersion": 1
    },
    {
      "id": "f50f3d1d-5d7b-42e5-aee5-ac747b429f8d",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        144,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 320,
        "content": "## Trigger and initiate detection\n\nStarts when a TikTok URL is submitted, downloading the video and beginning scene detection."
      },
      "typeVersion": 1
    },
    {
      "id": "5ddbd396-0c59-485b-b245-9e95e8aad347",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        688,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 640,
        "content": "## Scene detection status check\n\nWaits and checks if scene detection is complete, managing retries if detection isn't done."
      },
      "typeVersion": 1
    },
    {
      "id": "27b9b7e6-9e20-4629-98e3-d00f7b87cf1d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1376,
        -112
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 304,
        "content": "## Parse and split scene\n\nHandles parsing of detected scene cuts and splitting the video via HTTP request."
      },
      "typeVersion": 1
    },
    {
      "id": "12fdf9b1-9500-489d-b168-dda7384a180e",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1808,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 560,
        "content": "## Monitor and retry split\n\nMonitors the status of the video split, with retry logic if necessary."
      },
      "typeVersion": 1
    },
    {
      "id": "c04b5d79-2e97-4148-8669-d06b3cd4cb7d",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2528,
        -240
      ],
      "parameters": {
        "color": 7,
        "height": 336,
        "content": "## Display download link\n\nShows the link for downloading the split visual hook once processing is complete."
      },
      "typeVersion": 1
    },
    {
      "id": "af2da41a-2a6b-439f-8fc1-b9885e75d1b1",
      "name": "On TikTok URL Submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        192,
        96
      ],
      "parameters": {
        "options": {
          "buttonLabel": "Extract Visual Hook"
        },
        "formTitle": "TikTok Visual Hook Splitter",
        "formFields": {
          "values": [
            {
              "fieldLabel": "TikTok URL",
              "placeholder": "https://www.tiktok.com/@user/video/...",
              "requiredField": true
            }
          ]
        },
        "responseMode": "lastNode",
        "formDescription": "Paste a TikTok URL where the first 1-6 seconds are a reaction shot (smile, cry, gasp) and the rest is an app/product demo. The workflow auto-detects the reaction-to-demo cut with FFmpeg, then trims the source at that exact time. Ready to feed into Kling motion control with your AI avatar to mass-produce on-brand UGC reactions."
      },
      "executeOnce": true,
      "typeVersion": 2.3
    },
    {
      "id": "6cab0477-cbdd-4b34-9261-025bfd082e97",
      "name": "Download & Detect Scenes",
      "type": "n8n-nodes-renderio.renderio",
      "position": [
        480,
        80
      ],
      "parameters": {
        "mediaUrls": {
          "urlValues": [
            {
              "key": "in_video",
              "value": "={{ $json[\"TikTok URL\"] }}"
            }
          ]
        },
        "operation": "downloadAndProcessMedia",
        "outputFiles": {
          "fileValues": [
            {
              "value": "source.mp4"
            },
            {
              "key": "out_scenes",
              "value": "scenes.txt"
            }
          ]
        },
        "ffmpegCommand": "-i <<in_video>> -c copy -map 0 <<out_video>> -vf \"select='gt(scene,0.3)',metadata=print:file=<<out_scenes>>\" -an -f null -"
      },
      "credentials": {
        "renderioApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "bc03e16c-5fc3-4111-a706-c4b78d858c96",
      "name": "Wait 5 Seconds for Detection",
      "type": "n8n-nodes-base.wait",
      "position": [
        736,
        96
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "7a2c6037-aa49-406c-bf32-3b723f70703a",
      "name": "Verify Scene Detection Status",
      "type": "n8n-nodes-renderio.renderio",
      "position": [
        960,
        96
      ],
      "parameters": {
        "commandId": "={{ $('Download & Detect Scenes').item.json.command_id }}",
        "operation": "get"
      },
      "credentials": {
        "renderioApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "10e2722d-2ae2-4e21-bab9-6ef303b1c1fb",
      "name": "If Scenes Detected",
      "type": "n8n-nodes-base.if",
      "position": [
        1168,
        96
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d1",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "PROCESSING"
            },
            {
              "id": "d2",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "QUEUED"
            },
            {
              "id": "d3",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "RUNNING"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "d6cadbb5-0b79-439c-8a03-2c9936be8f5a",
      "name": "Extract Initial Scene Cut",
      "type": "n8n-nodes-base.code",
      "position": [
        1424,
        16
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const scenesUrl = $input.item.json.output_files.out_scenes.storage_url;\nconst sourceVideoUrl = $input.item.json.output_files.out_video.storage_url;\nconst raw = await this.helpers.httpRequest({ method: 'GET', url: scenesUrl, returnFullResponse: false });\nconst text = typeof raw === 'string' ? raw : JSON.stringify(raw);\nconst minS = 1;\nconst maxS = 6;\nconst times = [];\nconst re = /pts_time:([0-9]+\\.?[0-9]*)/g;\nlet m;\nwhile ((m = re.exec(text)) !== null) times.push(parseFloat(m[1]));\nlet hookEnd, reason;\nif (times.length === 0) { hookEnd = maxS; reason = 'no_scene_cut_fallback_to_max'; }\nelse {\n  const first = times[0];\n  if (first < minS) {\n    const next = times.find(t => t >= minS);\n    hookEnd = next != null ? Math.min(next, maxS) : maxS;\n    reason = next != null ? 'first_cut_too_early_used_next' : 'first_cut_too_early_used_max';\n  } else {\n    hookEnd = Math.min(first, maxS);\n    reason = first <= maxS ? 'first_scene_cut' : 'first_cut_above_max_capped';\n  }\n}\nconst hookEndSec = Math.round(hookEnd * 1000) / 1000;\nreturn { json: { hookEndSec, allSceneCuts: times, reason, sourceVideoUrl } };"
      },
      "typeVersion": 2
    },
    {
      "id": "7351537e-ed3e-4fde-b195-c58a9174d5ee",
      "name": "Execute Visual Hook Split",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1632,
        16
      ],
      "parameters": {
        "url": "https://renderio.dev/api/v1/run-ffmpeg-command",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({ input_files: { in_video: $json.sourceVideoUrl }, output_files: { out_hook: 'visual_hook.mp4' }, ffmpeg_command: '-i <<in_video>> -t ' + $json.hookEndSec + ' -c:v libx264 -preset veryfast -crf 20 -c:a aac -b:a 128k -movflags +faststart <<out_hook>>' }) }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "renderioApi"
      },
      "credentials": {
        "renderioApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "d28b1e2e-8fe6-44ab-b575-57721fe97a82",
      "name": "Wait 5 Seconds for Split",
      "type": "n8n-nodes-base.wait",
      "position": [
        1856,
        16
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "7d02229f-6cca-4da1-8872-92d9d9d30027",
      "name": "Verify Split Execution Status",
      "type": "n8n-nodes-renderio.renderio",
      "position": [
        2080,
        16
      ],
      "parameters": {
        "commandId": "={{ $('Execute Visual Hook Split').item.json.command_id }}",
        "operation": "get"
      },
      "credentials": {
        "renderioApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "504eaea0-8fe2-4f64-b429-f1a9ac55ffe2",
      "name": "If Split Successful",
      "type": "n8n-nodes-base.if",
      "position": [
        2304,
        16
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "s1",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "PROCESSING"
            },
            {
              "id": "s2",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "QUEUED"
            },
            {
              "id": "s3",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "RUNNING"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "154647d0-6a5d-498e-997f-53cf1abb352b",
      "name": "Show Hook Download Link",
      "type": "n8n-nodes-base.form",
      "position": [
        2576,
        -64
      ],
      "parameters": {
        "options": {},
        "operation": "completion",
        "completionTitle": "Visual hook extracted",
        "completionMessage": "=Status: **{{ $json.status }}**\n\nHook end time: **{{ $('Extract Initial Scene Cut').item.json.hookEndSec }}s** (detection: {{ $('Extract Initial Scene Cut').item.json.reason }})\n\nAll scene cuts detected: {{ JSON.stringify($('Extract Initial Scene Cut').item.json.allSceneCuts) }}\n\n[Download visual hook MP4]({{ $json.output_files.out_hook.storage_url }})\n\nFeed this clip into RenderIO + Kling motion control with your AI avatar to mass-produce on-brand UGC reactions."
      },
      "typeVersion": 2.3
    },
    {
      "id": "f79562de-cde4-4e80-a8d5-c3f45f944cf7",
      "name": "Wait 10 Seconds for Split Retry",
      "type": "n8n-nodes-base.wait",
      "position": [
        2336,
        304
      ],
      "parameters": {
        "amount": 10
      },
      "typeVersion": 1.1
    },
    {
      "id": "6a4b1432-6263-472d-bd89-eb8372582838",
      "name": "Wait 10 Seconds for Detect Retry",
      "type": "n8n-nodes-base.wait",
      "position": [
        1184,
        432
      ],
      "parameters": {
        "amount": 10
      },
      "typeVersion": 1.1
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "448503f5-1e7a-4c36-8959-90d209181869",
  "connections": {
    "If Scenes Detected": {
      "main": [
        [
          {
            "node": "Extract Initial Scene Cut",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait 10 Seconds for Detect Retry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Split Successful": {
      "main": [
        [
          {
            "node": "Show Hook Download Link",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait 10 Seconds for Split Retry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download & Detect Scenes": {
      "main": [
        [
          {
            "node": "Wait 5 Seconds for Detection",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On TikTok URL Submission": {
      "main": [
        [
          {
            "node": "Download & Detect Scenes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 5 Seconds for Split": {
      "main": [
        [
          {
            "node": "Verify Split Execution Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute Visual Hook Split": {
      "main": [
        [
          {
            "node": "Wait 5 Seconds for Split",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Initial Scene Cut": {
      "main": [
        [
          {
            "node": "Execute Visual Hook Split",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 5 Seconds for Detection": {
      "main": [
        [
          {
            "node": "Verify Scene Detection Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify Scene Detection Status": {
      "main": [
        [
          {
            "node": "If Scenes Detected",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify Split Execution Status": {
      "main": [
        [
          {
            "node": "If Split Successful",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 10 Seconds for Split Retry": {
      "main": [
        [
          {
            "node": "Verify Split Execution Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 10 Seconds for Detect Retry": {
      "main": [
        [
          {
            "node": "Verify Scene Detection Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Works on both n8n Cloud and self-hosted instances. This template uses the community node, which is installable on n8n Cloud and self-hosted setups.

Source: https://n8n.io/workflows/15883/ — original creator credit. Request a take-down →

More Social Media workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Social Media

🚀 Discover trending and viral YouTube videos easily with this powerful n8n automation! This workflow helps you perform bulk research on YouTube videos related to any search term, analyzing engagement

HTTP Request, Google Sheets, Form Trigger
Social Media

TikTok Visual Hook Splitter. Uses formTrigger, n8n-nodes-renderio, httpRequest, form. Event-driven trigger; 21 nodes.

Form Trigger, N8N Nodes Renderio, HTTP Request +1
Social Media

Disclaimer: this workflow only works on self-hosted instances due to the file system usage.

Execute Workflow Trigger, HTTP Request, Form Trigger +3
Social Media

Imagine you want to automate a task where, based on a TikTok video link, you must retrieve the username of the creator of that video.

HTTP Request, Form Trigger, Stop And Error +1
Social Media

Use cases are many: Whether you're a YouTube creator trying to understand your audience, a marketer running sample analysis, a data analyst compiling engagement metrics, or part of a growth team track

Google Sheets, HTTP Request