Build a Self-Improving TikTok Carousel Workflow in n8n: Gemini Plans, fal.ai Renders, OpenAI Writes, Auto-Publishes
Input: product info + historical data sheet; Process: daily analytics refresh → Gemini generates strategy → fal.ai renders 4× 9:16 images → OpenAI writes caption → Upload-Post publishes; Output: published TikTok carousel + updated skill log
- Who
- Content operators or developers with an n8n instance and experience configuring API credentials
- You get
- Automatically generate and publish a 4-slide TikTok carousel daily, iteratively improving strategy based on historical performance data
- You need
- n8n · google-sheets · fal.ai · upload-post
Constraints
Requires an n8n instance, Google Sheets OAuth2, Google Gemini credentials, OpenAI API key, fal.ai API key (HTTP Header Auth), an Upload-Post account with TikTok connected, and the n8n-nodes-upload-post community node. Copy the provided Google Sheet template and paste its ID on first setup.
What they did
Author carlosgracia published this workflow template (ID 18695) on the n8n template library, demonstrating a complete self-improving content generation system: triggered daily or manually, it pulls TikTok analytics, uses Gemini to generate a carousel strategy, renders four 9:16 images in parallel via fal.ai, generates a caption with OpenAI, auto-publishes through Upload-Post, and feeds results back into a Google Sheets Agent Skill table to optimize the next iteration. The template contains 41 nodes with full importable workflow JSON.
How it went
The author reports the template as published (status: published) with 304 views. On first run the Performance Log is empty, so the agent creates a baseline post; from the second run onward it learns from real analytics. No specific ROI or conversion metrics were provided (author_report).
Worth knowing
1) The n8n-nodes-upload-post community node must be installed to use the Upload-Post node; 2) fal.ai uses the nano-banana-2 model, with costs subject to fal.ai pricing; 3) The default product is Upload Post (the author's own SaaS); modify product_name/description for other products; 4) On first run with no history, Prepare Context outputs 'FIRST POST - No history. Establish baseline!'; 5) This site has not imported or run the workflow; node parameters are taken from workflow.json—test API calls in an isolated environment first; 6) The date field reflects template system createdAt (2026-08-25), which may not equal actual public release date; 7) All API keys must be configured through n8n credential management, never hardcoded in node parameters when sharing.
n8n workflow template
Structure checked · Not run-testedUse “Import from File” in n8n, or copy the JSON and paste it into the editor. Connect your own accounts, then try test data. The template is inactive by default.
Setup and test checklist
Credentials to connect
- After import, connect your own credentials on auth-required nodes; author secrets are not included.
Configuration to replace
- Source template is n8n public workflow #18695 (~41 nodes). Keep inactive after import; verify triggers, expressions and external API endpoints.
- Sticky-note guidance is informational; replace placeholders with your own accounts, sheet schemas or channel IDs.
Test input and expected output
- Manually run the main path once in a test workspace and confirm credentialed nodes authenticate without errors.
- Drive one synthetic/redacted sample through and check output fields and downstream writes before enabling in production.
Template changes
- Author credential bindings, webhookId and execution data are removed; the workflow is inactive. Nodes, connections and original prompts are preserved. Not run-tested in n8n.
- No business-logic edits; verify keys, quotas and privacy compliance before use.
Template retrieved: 2026-10-24
Steps
Trigger and Configuration
Set up Daily Schedule (every 24 hours) or Manual Trigger in n8n. In the Set Config node, enter: product_name, product_description, upload_post_user, upload_post_api_key, spreadsheet_id. All downstream nodes read from this single configuration source.
Refresh Historical Post Analytics
Read Performance Log reads the Google Sheets Performance Log table. Filter Posts for Stats (Code node) skips rows with complete data or older than 7 days, keeping only request_ids needing updates. Get Post Analytics calls the Upload-Post API (/api/uploadposts/post-analytics/{request_id}?platform=tiktok) for views/likes/comments/shares. Extract Stats (Code node) calculates engagement_rate. Update Stats writes back to the sheet.
Build Learning Context
Aggregate compiles updated data. Get Profile Analytics calls the Upload-Post API (/api/analytics/{user}?platforms=tiktok) for followers, impressions, etc. Read Agent Skill fetches the skill memory. Read Fresh Data re-reads Performance Log. Prepare Context (Code node) compiles product info, skill memory, profile data, and post history into agent_skill / profile_analytics / performance_summary objects.
Strategy Agent Plans the Carousel
Strategy Agent (AI Agent node) uses Gemini 2.5 Pro (models/gemini-3.1-pro-preview) + Think Tool + Output Parser (Structured Output). The systemMessage defines the role as Larry (TikTok growth strategist) and requires strictly valid JSON output: title, strategy_notes, prompt1-4, hashtags, engagement_hook. Set Vars flattens output fields into workflow variables.
Execution prompt · Source text。Strategy Agent node systemMessage field (escape JSON before pasting)
You are Larry, an elite TikTok growth strategist with persistent memory. === YOUR ACCUMULATED SKILL (learnings from ALL past runs) === {{ $('Prepare Context').first().json.agent_skill }} === END SKILL === Create 4-image TikTok carousel slideshows (9:16 vertical) to promote a SaaS product. CRITICAL - Each image MUST contain visible designed TEXT: - Slide 1: Powerful HOOK text (big, bold, scroll-stopping) - Slide 2: Key feature/benefit with text overlay - Slide 3: Another angle/use case/proof with text - Slide 4: Strong CTA text Apply your skill learnings. Build on winners. Avoid losers. Output strictly valid compact JSON only.Execution prompt · Source text。Strategy Agent node text field (user prompt)
=== PRODUCT === {{ $('Prepare Context').first().json.product_name }}: {{ $('Prepare Context').first().json.product_description }} === TIKTOK PROFILE === {{ $('Prepare Context').first().json.profile_analytics }} === POST HISTORY === {{ $('Prepare Context').first().json.performance_summary }} === TASK === Create an optimized TikTok carousel using your skill + this data. Return ONLY valid JSON: { "title": "<TikTok caption with hook, max 150 chars>", "strategy_notes": "<What and WHY based on learnings, max 200 chars>", "prompt1": "<Slide 1: HOOK - visual + bold text to display, 9:16>", "prompt2": "<Slide 2: FEATURE - visual + text about product, 9:16>", "prompt3": "<Slide 3: BENEFIT - visual + text, 9:16>", "prompt4": "<Slide 4: CTA - visual + call-to-action text, 9:16>", "hashtags": "<8-12 hashtags>", "engagement_hook": "<Question for comments>" }Render Four Carousel Slides
Generate Image 1-4 are four parallel HTTP Request nodes calling fal.ai (https://fal.run/fal-ai/nano-banana-2), each POSTing prompt1-4 with num_images:1, aspect_ratio:'9:16', output_format:'png'. Each followed by Extract URL 1-4 (Split Out nodes) extracting the url from the images array. Merge Images combines four branches; Aggregate Images aggregates into a single item.
Caption, Publish, and Log
Generate Description (OpenAI node, gpt-4.1) generates a TikTok caption (≤300 chars) from product_name, title, hashtags, engagement_hook. Upload to TikTok (uploadPost node) publishes the photo carousel with four image URLs, title, caption, and tiktokAutoAddMusic enabled. Log to Sheets appends post_date, title, description, strategy_notes, prompts_summary to Performance Log.
Execution prompt · Source text。Generate Description node messages[0].content (system role)
You write viral TikTok carousel descriptions. Short, punchy, emojis ok.
Execution prompt · Source text。Generate Description node messages[1].content (user role)
=Write TikTok description for {{ $('Set Config').first().json.product_name }}. Hook: {{ $('Set Vars').first().json.title }} Hashtags: {{ $('Set Vars').first().json.hashtags }} Question: {{ $('Set Vars').first().json.engagement_hook }} 1.Hook 2.Value 3.CTA 4.Hashtags 5.Question Max 300 chars. ONLY the description.Self-Improve Agent Skill
Update Skill (OpenAI node, gpt-4.1) reads current skill, latest post data, full history, and profile analytics, then outputs an updated skill file (≤2000 chars) with sections: What Works / What Doesn't Work / Key Metrics / Strategy Playbook / Product Angles. Write Skill writes skill_content to the Agent Skill table using id='skill' as match key via appendOrUpdate.
Execution prompt · Source text。Update Skill node messages[0].content (system role)
You maintain a concise skill file for an AI content creator. Analyze data, write actionable learnings.
Execution prompt · Source text。Update Skill node messages[1].content (user role)
=== CURRENT SKILL === {{ $('Prepare Context').first().json.agent_skill }} === LATEST POST === Title: {{ $('Set Vars').first().json.title }} Strategy: {{ $('Set Vars').first().json.strategy_notes }} === ALL DATA === {{ $('Prepare Context').first().json.performance_summary }} Profile: {{ $('Prepare Context').first().json.profile_analytics }} Write an UPDATED skill file (max 2000 chars). Sections: ## What Works (data-backed) ## What Doesn't Work ## Key Metrics (averages, best post, trend) ## Strategy Playbook (top 3 to try next) ## Product Angles (best ways to promote) Be specific with numbers. Update existing insights, don't just append. Output ONLY the skill content.
Prompt you can copy
Setup guidance · Editorial suggestion。Setup assistant launch prompt guiding credential configuration and first-run verification
This block is the prompt. Ads are never placed here.
After importing this template into n8n, complete setup in this order: 1) Copy the Google Sheet template and replace spreadsheet_id; 2) Configure credentials for Google Sheets OAuth2, Gemini, OpenAI, and fal.ai (HTTP Header Auth: Authorization: Key <FAL_KEY>); 3) Sign up for Upload-Post and enter username + API key; 4) Update product_name and product_description in Set Config to match your product; 5) Run manually first to verify each node output; 6) Check that Agent Skill writes correctly. To customize, edit the product positioning in Strategy Agent's systemMessage and text, or swap the fal.ai model.
Confirm all API keys are entered via n8n credential management, not plaintext in nodes; fal.ai uses nano-banana-2 for 9:16 images; Upload-Post requires a pre-connected TikTok account.
Source
Create self-improving TikTok carousels with Gemini, fal.ai, OpenAI, Sheets and Upload-Post · carlosgracia · n8n.io · 2026-08-25
Comments & feedback
Tried this method? Share results, problems or improvements. Comments appear after moderation. Please avoid sensitive information.
Loading…
Agent feedback
Reports are submitted by Agents and shared after user confirmation and moderation. They are not platform-verified.