This workflow corresponds to n8n.io template #15404 — we link there as the canonical source.
This workflow follows the Agent → 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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "69c4be0a-72e2-4dc6-87b9-3cbbe9f47f26",
"name": "Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1360,
-480
],
"parameters": {
"color": 4,
"width": 540,
"height": 1044,
"content": "## TikTok Video to Facebook Caption Auto-Poster \u2014 WayinVideo + GPT-4o-mini + Facebook Graph API + Sheets\n\nFor social media managers, content creators, and brands who produce TikTok or short-form videos and want to automatically repurpose each one into a published Facebook post \u2014 without manually rewriting captions. Paste any TikTok, YouTube, or short-form video URL via the form. WayinVideo transcribes the full video content. A plain text version of the transcript (without speaker labels) is sent to GPT-4o-mini which writes an engaging Facebook post caption \u2014 with a hook, short paragraphs, a CTA, optional video link, and up to 8 hashtags \u2014 following Facebook best practices for engagement. The caption is posted directly to your Facebook Page via the Graph API. Every post is logged to Google Sheets with the Post ID, Post URL, character count, and Posted status.\n\n## How it works\n- **1. Form \u2014 Video URL + Details** collects the video URL, title, brand name, target audience, post tone, and whether to include the video link\n- **2. WayinVideo \u2014 Submit Transcription** submits the URL for transcription\n- **3. Wait \u2014 60 Seconds** gives the API initial processing time\n- **4. WayinVideo \u2014 Get Transcript Results** polls for the task result\n- **5. IF \u2014 Transcription Complete?** checks for SUCCEEDED \u2014 if not, retries via 30-second wait\n- **7. Code \u2014 Format Transcript** formats speaker-labeled text and also builds a plain text version for caption writing\n- **8. AI Agent \u2014 Write Facebook Caption** uses GPT-4o-mini with 10 Facebook writing rules to produce a caption, hashtags, and character count in labeled sections\n- **10. Code \u2014 Parse Caption Output** extracts caption, hashtags, and character count via regex and builds the full post message\n- **11. HTTP \u2014 Post to Facebook** posts the caption to the Facebook Page feed via Graph API v19\n- **12. Google Sheets \u2014 Log Post** appends one row with all fields including Post ID and constructed Post URL\n\n## Set up steps\n1. In **2. WayinVideo \u2014 Submit Transcription** and **4. WayinVideo \u2014 Get Transcript Results** \u2014 replace YOUR_WAYINVIDEO_API_KEY\n2. In **9. OpenAI \u2014 GPT-4o-mini Model** \u2014 connect your OpenAI credential\n3. In **11. HTTP \u2014 Post to Facebook** \u2014 replace YOUR_FACEBOOK_PAGE_ID in the URL and YOUR_FACEBOOK_PAGE_ACCESS_TOKEN in the body\n4. In **12. Google Sheets \u2014 Log Post** \u2014 connect your Google Sheets OAuth2 credential and replace YOUR_GOOGLE_SHEET_ID\n5. Create a Google Sheet tab named Facebook Posts with columns: Video URL, Video Title, Brand / Page, Facebook Caption, Hashtags, Character Count, Post ID, Post URL, Status, Posted On"
},
"typeVersion": 1
},
{
"id": "ddfe2ef3-81af-4020-9215-b7b5d109a5cf",
"name": "Section \u2014 Form Input",
"type": "n8n-nodes-base.stickyNote",
"position": [
-768,
-272
],
"parameters": {
"color": 5,
"width": 324,
"height": 484,
"content": "## Form Input\nUser submits video URL, title, brand name, target audience, post tone, and whether to include the video link. All six fields feed into the transcript formatter and AI caption prompt."
},
"typeVersion": 1
},
{
"id": "067cb186-73bb-4657-81f1-1f6c5f91c99f",
"name": "Section \u2014 Transcription Submit and Poll",
"type": "n8n-nodes-base.stickyNote",
"position": [
-416,
-272
],
"parameters": {
"color": 6,
"width": 660,
"height": 484,
"content": "## WayinVideo Transcription Submit and Poll\nSubmits the video URL for transcription. Waits 60 seconds for initial processing. Polls the results endpoint until status equals SUCCEEDED."
},
"typeVersion": 1
},
{
"id": "f4937bb4-b56b-46cf-9396-c5eafbdda55e",
"name": "Section \u2014 Status Check and Retry Loop",
"type": "n8n-nodes-base.stickyNote",
"position": [
256,
-272
],
"parameters": {
"color": 6,
"width": 372,
"height": 644,
"content": "## Transcription Status Check and Retry Loop\nIF checks for SUCCEEDED status. TRUE proceeds to transcript formatting. FALSE waits 30 seconds and polls again. Loop continues until the transcript is ready."
},
"typeVersion": 1
},
{
"id": "096330e5-c876-4199-b9ea-e3f7bc045b2c",
"name": "Section \u2014 Transcript Formatting and AI Caption Writing",
"type": "n8n-nodes-base.stickyNote",
"position": [
640,
-272
],
"parameters": {
"color": 6,
"width": 676,
"height": 644,
"content": "## Transcript Formatting and AI Caption Writing\nBuilds both a speaker-labeled transcript and a clean plain text version. GPT-4o-mini uses the plain text to write a Facebook caption with hook, short paragraphs, CTA, optional video link, and up to 8 hashtags following 10 Facebook engagement rules."
},
"typeVersion": 1
},
{
"id": "c08efb57-a760-4032-a62c-2668a91bc69a",
"name": "Section \u2014 Caption Parse, Facebook Post, and Sheet Log",
"type": "n8n-nodes-base.stickyNote",
"position": [
1360,
-256
],
"parameters": {
"color": 4,
"width": 692,
"height": 436,
"content": "## Caption Parse, Facebook Post, and Sheet Log\nRegex extracts caption, hashtags, and character count. HTTP posts the full message to the Facebook Page feed via Graph API v19. Google Sheets logs every post with Post ID, constructed Post URL, and Posted status."
},
"typeVersion": 1
},
{
"id": "1b6300c6-109c-4a5e-bef9-38a641e82e82",
"name": "1. Form \u2014 Video URL + Details",
"type": "n8n-nodes-base.formTrigger",
"position": [
-672,
-96
],
"parameters": {
"options": {},
"formTitle": "TikTok to Facebook Caption Auto-Poster",
"formFields": {
"values": [
{
"fieldLabel": "Video URL",
"placeholder": "https://www.tiktok.com/@username/video/xxxxxxx or YouTube/Vimeo link",
"requiredField": true
},
{
"fieldLabel": "Video Title",
"placeholder": "e.g. 5 Morning Habits That Changed My Life",
"requiredField": true
},
{
"fieldLabel": "Brand / Page Name",
"placeholder": "e.g. Incrementors, My Fitness Brand, TechStartup",
"requiredField": true
},
{
"fieldLabel": "Target Audience",
"placeholder": "e.g. Small business owners, fitness enthusiasts, tech professionals",
"requiredField": true
},
{
"fieldLabel": "Post Tone",
"placeholder": "e.g. Inspiring and motivational / Informative / Funny and casual / Professional",
"requiredField": true
},
{
"fieldLabel": "Include Video Link in Post?",
"placeholder": "Yes or No",
"requiredField": true
}
]
},
"formDescription": "Paste your TikTok or video URL. AI will transcribe the content and automatically write and post a Facebook caption to your Page."
},
"typeVersion": 2.2
},
{
"id": "90e68a49-1d3d-44b4-ae99-e7a926d4f442",
"name": "2. WayinVideo \u2014 Submit Transcription",
"type": "n8n-nodes-base.httpRequest",
"position": [
-368,
-96
],
"parameters": {
"url": "https://wayinvideo-api.wayin.ai/api/v2/transcripts",
"method": "POST",
"options": {},
"jsonBody": "={\n \"video_url\": \"{{ $json['Video URL'] }}\",\n \"target_lang\": \"en\"\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer YOUR_TOKEN_HERE"
},
{
"name": "x-wayinvideo-api-version",
"value": "v2"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "48adad30-6c76-472c-a223-c8be349100f3",
"name": "3. Wait \u2014 60 Seconds",
"type": "n8n-nodes-base.wait",
"position": [
-128,
-96
],
"parameters": {
"amount": 60
},
"typeVersion": 1.1
},
{
"id": "e3ae4fa3-652e-4da5-8acc-04f13738a993",
"name": "4. WayinVideo \u2014 Get Transcript Results",
"type": "n8n-nodes-base.httpRequest",
"position": [
112,
-96
],
"parameters": {
"url": "=https://wayinvideo-api.wayin.ai/api/v2/transcripts/results/{{ $('2. WayinVideo \u2014 Submit Transcription').item.json.data.id }}",
"options": {},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer YOUR_TOKEN_HERE"
},
{
"name": "x-wayinvideo-api-version",
"value": "v2"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "3b31e751-9744-41d5-b374-cddacd002191",
"name": "5. IF \u2014 Transcription Complete?",
"type": "n8n-nodes-base.if",
"position": [
352,
-96
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "status-check",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.status }}",
"rightValue": "SUCCEEDED"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "82ea9cfb-79ab-4846-9a00-cef38c491054",
"name": "6. Wait \u2014 30 Seconds Retry",
"type": "n8n-nodes-base.wait",
"position": [
352,
112
],
"parameters": {
"amount": 30
},
"typeVersion": 1.1
},
{
"id": "1a9ff3e4-0c55-4bbe-a7c5-f7808a5aa6d1",
"name": "7. Code \u2014 Format Transcript",
"type": "n8n-nodes-base.code",
"position": [
672,
-112
],
"parameters": {
"jsCode": "// Get transcript segments from WayinVideo\nconst segments = $('4. WayinVideo \u2014 Get Transcript Results').item.json.data.transcript || [];\n\nif (segments.length === 0) {\n throw new Error('Transcript is empty \u2014 check if the video URL is valid and publicly accessible.');\n}\n\n// Format transcript \u2014 clean readable text for GPT\nconst formattedTranscript = segments\n .map(s => {\n const timeInSeconds = Math.floor(s.start / 1000);\n const minutes = Math.floor(timeInSeconds / 60);\n const seconds = timeInSeconds % 60;\n const timestamp = `${minutes}:${seconds.toString().padStart(2, '0')}`;\n return `[${s.speaker} | ${timestamp}] ${s.text.trim()}`;\n })\n .join('\\n');\n\n// Plain text version for caption writing\nconst plainText = segments.map(s => s.text.trim()).join(' ');\n\n// Duration\nconst lastSegment = segments[segments.length - 1];\nconst totalDurationMs = lastSegment?.end || 0;\nconst totalMinutes = Math.round(totalDurationMs / 60000);\n\n// Speakers\nconst speakers = [...new Set(segments.map(s => s.speaker))];\n\nreturn [{\n json: {\n formattedTranscript,\n plainText,\n totalMinutes,\n speakerCount: speakers.length,\n videoTitle: $('1. Form \u2014 Video URL + Details').item.json['Video Title'],\n videoUrl: $('1. Form \u2014 Video URL + Details').item.json['Video URL'],\n brandName: $('1. Form \u2014 Video URL + Details').item.json['Brand / Page Name'],\n targetAudience: $('1. Form \u2014 Video URL + Details').item.json['Target Audience'],\n postTone: $('1. Form \u2014 Video URL + Details').item.json['Post Tone'],\n includeLink: $('1. Form \u2014 Video URL + Details').item.json['Include Video Link in Post?']\n }\n}];"
},
"typeVersion": 2
},
{
"id": "52ff4a9e-6115-4ccc-816d-341297fdea80",
"name": "8. AI Agent \u2014 Write Facebook Caption",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
912,
-112
],
"parameters": {
"text": "={{ $json.plainText }}",
"options": {
"systemMessage": "=You are an expert Facebook content writer who specializes in writing high-engagement posts for brands and creators.\n\nYour job is to read the video transcript below and write a compelling Facebook post caption that drives likes, comments, and shares.\n\n---\n\n## VIDEO DETAILS\n- Video Title: {{ $json.videoTitle }}\n- Brand / Page: {{ $json.brandName }}\n- Target Audience: {{ $json.targetAudience }}\n- Post Tone: {{ $json.postTone }}\n- Video Duration: {{ $json.totalMinutes }} minutes\n- Include Video Link: {{ $json.includeLink }}\n- Video URL: {{ $json.videoUrl }}\n\n---\n\n## FACEBOOK POST WRITING RULES\n1. Write ONLY from what is said in the video transcript \u2014 no invented content\n2. Start with a strong HOOK in the first line \u2014 make people stop scrolling. Use a question, a bold statement, or a surprising fact.\n3. Keep paragraphs short \u2014 1-2 sentences maximum. Facebook readers skim.\n4. Use line breaks between each paragraph for readability\n5. Match the tone specified above consistently throughout\n6. End with a clear CTA \u2014 ask people to comment, share, tag someone, or click a link\n7. Add emojis naturally \u2014 not too many, only where they add energy\n8. Total post length: 150-300 words \u2014 long enough to engage, short enough to read\n9. If Include Video Link = Yes \u2014 add the video URL naturally at the end of the post\n10. Hashtags must be relevant and lowercase \u2014 no more than 8 hashtags\n\n---\n\n## OUTPUT FORMAT\nReturn your response in this exact structure \u2014 use these exact labels:\n\nFACEBOOK CAPTION:\n[Write the full Facebook post caption here \u2014 hook, body paragraphs, CTA, optional video link]\n\nHASHTAGS:\n[List 5-8 relevant hashtags \u2014 lowercase \u2014 space separated]\n\nCHARACTER COUNT:\n[Total character count of the caption only \u2014 not including hashtags]\n\n---\n\nNow read the video transcript and write the Facebook post caption:"
},
"promptType": "define"
},
"typeVersion": 3.1
},
{
"id": "34324b12-ca31-484c-84af-ffdf018548cc",
"name": "9. OpenAI \u2014 GPT-4o-mini Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
912,
96
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {},
"builtInTools": {}
},
"typeVersion": 1.3
},
{
"id": "265e193e-fdb0-443a-92d2-5d111baf7bc3",
"name": "10. Code \u2014 Parse Caption Output",
"type": "n8n-nodes-base.code",
"position": [
1408,
-112
],
"parameters": {
"jsCode": "// Parse AI output \u2014 extract caption and hashtags\nconst output = $input.first().json.output || '';\n\n// Extract FACEBOOK CAPTION\nconst captionMatch = output.match(/FACEBOOK CAPTION:\\s*([\\s\\S]*?)(?=\\nHASHTAGS:|$)/);\nconst caption = captionMatch ? captionMatch[1].trim() : '';\n\n// Extract HASHTAGS\nconst hashtagsMatch = output.match(/HASHTAGS:\\s*([\\s\\S]*?)(?=\\nCHARACTER COUNT:|$)/);\nconst hashtags = hashtagsMatch ? hashtagsMatch[1].trim() : '';\n\n// Extract CHARACTER COUNT\nconst charCountMatch = output.match(/CHARACTER COUNT:\\s*([\\d]+)/);\nconst charCount = charCountMatch ? parseInt(charCountMatch[1]) : caption.length;\n\n// Build full post message \u2014 caption + hashtags\nconst fullMessage = `${caption}\\n\\n${hashtags}`.trim();\n\nif (!caption) {\n throw new Error('Could not parse Facebook caption from AI output. Check AI prompt output format.');\n}\n\nreturn [{\n json: {\n caption,\n hashtags,\n fullMessage,\n charCount,\n videoTitle: $('7. Code \u2014 Format Transcript').item.json.videoTitle,\n videoUrl: $('7. Code \u2014 Format Transcript').item.json.videoUrl,\n brandName: $('7. Code \u2014 Format Transcript').item.json.brandName,\n postTone: $('7. Code \u2014 Format Transcript').item.json.postTone\n }\n}];"
},
"typeVersion": 2
},
{
"id": "ab9babc8-4369-4ccb-8a30-6292b87f9c4a",
"name": "11. HTTP \u2014 Post to Facebook",
"type": "n8n-nodes-base.httpRequest",
"position": [
1648,
-112
],
"parameters": {
"url": "=https://graph.facebook.com/v19.0/YOUR_FACEBOOK_PAGE_ID/feed",
"method": "POST",
"options": {},
"jsonBody": "={\n \"message\": \"{{ $json.fullMessage }}\",\n \"access_token\": \"YOUR_FACEBOOK_PAGE_ACCESS_TOKEN\"\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "9c9a7402-c86d-46ee-b75c-afb5bb71c8cb",
"name": "12. Google Sheets \u2014 Log Post",
"type": "n8n-nodes-base.googleSheets",
"position": [
1888,
-112
],
"parameters": {
"columns": {
"value": {
"Status": "Posted",
"Post ID": "={{ $json.id }}",
"Hashtags": "={{ $('10. Code \u2014 Parse Caption Output').item.json.hashtags }}",
"Post URL": "=https://www.facebook.com/{{ $json.id }}",
"Posted On": "={{ $now.toFormat('dd MMMM yyyy HH:mm') }}",
"Video URL": "={{ $('10. Code \u2014 Parse Caption Output').item.json.videoUrl }}",
"Video Title": "={{ $('10. Code \u2014 Parse Caption Output').item.json.videoTitle }}",
"Brand / Page": "={{ $('10. Code \u2014 Parse Caption Output').item.json.brandName }}",
"Character Count": "={{ $('10. Code \u2014 Parse Caption Output').item.json.charCount }}",
"Facebook Caption": "={{ $('10. Code \u2014 Parse Caption Output').item.json.caption }}"
},
"schema": [],
"mappingMode": "defineBelow",
"matchingColumns": []
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "Facebook Posts"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_GOOGLE_SHEET_ID"
}
},
"typeVersion": 4.5
}
],
"connections": {
"3. Wait \u2014 60 Seconds": {
"main": [
[
{
"node": "4. WayinVideo \u2014 Get Transcript Results",
"type": "main",
"index": 0
}
]
]
},
"6. Wait \u2014 30 Seconds Retry": {
"main": [
[
{
"node": "4. WayinVideo \u2014 Get Transcript Results",
"type": "main",
"index": 0
}
]
]
},
"11. HTTP \u2014 Post to Facebook": {
"main": [
[
{
"node": "12. Google Sheets \u2014 Log Post",
"type": "main",
"index": 0
}
]
]
},
"7. Code \u2014 Format Transcript": {
"main": [
[
{
"node": "8. AI Agent \u2014 Write Facebook Caption",
"type": "main",
"index": 0
}
]
]
},
"1. Form \u2014 Video URL + Details": {
"main": [
[
{
"node": "2. WayinVideo \u2014 Submit Transcription",
"type": "main",
"index": 0
}
]
]
},
"9. OpenAI \u2014 GPT-4o-mini Model": {
"ai_languageModel": [
[
{
"node": "8. AI Agent \u2014 Write Facebook Caption",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"10. Code \u2014 Parse Caption Output": {
"main": [
[
{
"node": "11. HTTP \u2014 Post to Facebook",
"type": "main",
"index": 0
}
]
]
},
"5. IF \u2014 Transcription Complete?": {
"main": [
[
{
"node": "7. Code \u2014 Format Transcript",
"type": "main",
"index": 0
}
],
[
{
"node": "6. Wait \u2014 30 Seconds Retry",
"type": "main",
"index": 0
}
]
]
},
"2. WayinVideo \u2014 Submit Transcription": {
"main": [
[
{
"node": "3. Wait \u2014 60 Seconds",
"type": "main",
"index": 0
}
]
]
},
"8. AI Agent \u2014 Write Facebook Caption": {
"main": [
[
{
"node": "10. Code \u2014 Parse Caption Output",
"type": "main",
"index": 0
}
]
]
},
"4. WayinVideo \u2014 Get Transcript Results": {
"main": [
[
{
"node": "5. IF \u2014 Transcription Complete?",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Paste any TikTok, YouTube, or short-form video URL into a simple form along with your brand name, target audience, and preferred tone and the workflow automatically transcribes the content and writes a ready-to-publish Facebook caption. GPT-4o-mini follows ten Facebook…
Source: https://n8n.io/workflows/15404/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
🎯 Create viral TikToks, Shorts, Reels, podcasts, and ASMR videos in minutes — all on autopilot.
Digistars - Scrape & Crawl. Uses httpRequest, n8n-nodes-firecrawl-scraper, googleSheets, lmChatOpenAi. Event-driven trigger; 63 nodes.
🧠 Automate end-to-end SEO blog creation and WordPress publishing using a GPT-5 multi-agent workflow with real-time research, metadata generation, and optional featured images.
The workflow runs every hour with a randomized delay of 5–20 minutes to help distribute load. It records the exact date and time a lead is emailed so you can track outreach. Follow-ups are automatical
This n8n workflow automates turning short user ideas into production-ready real-estate marketing assets (photorealistic images and optional 360° videos). A form submission seeds a prompt board → an LL