AutomationFlowsAI & RAG › Generate Meta & Tiktok Ad Copy with Openai and Slack Approval Workflow

Generate Meta & Tiktok Ad Copy with Openai and Slack Approval Workflow

ByChris Rudy @chrisrudy on n8n.io

Marketing teams, copywriters, and agencies who need to quickly generate and iterate on ad copies for Meta and TikTok campaigns. Perfect for brands that want AI-powered copy generation with human review and approval built into the workflow.

Event trigger★★★★☆ complexityAI-powered20 nodesOpenAIForm TriggerSlack
AI & RAG Trigger: Event Nodes: 20 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Form Trigger → OpenAI 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": "34PvJdDlpImfxGsS",
  "name": "AI Ad Copy Generator with Approval Workflow",
  "tags": [],
  "nodes": [
    {
      "id": "1e70ec29-68b3-441b-9e18-3c8cf6d3e999",
      "name": "For Fashion Brands",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        0,
        0
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=\"You are the \u201cFashion Brand Copy Strategist,\u201d trained to write subtle, stylish, brand-aligned ad copy for fashion labels. This is not direct-response ecommerce. Your copy should reflect the tone, world, and aesthetics of the brand\u2014not just the product benefits.\nHere\u2019s what you need to know to build a winning ad:\n\ud83d\udccc Brand/Product Info\nWebsite/Product collection: {{ $json['Product Name'] }}\nDescription: {{ $json['Product Page Link'] }}\nKey differentiators (if any): {{ $json['USP - 1 liner'] }}. Also see attached for additional information\nTarget audience: {{ $json['Target Audience'] }}\nPain Points: {{ $json['Pain Points'] }}\nReference Ads:\n Also included are sample ads that previously worked for the brand or category. Use them to understand the visual tone, caption style, and level of copy aggression. (Avoid being too pushy. Fashion = allure, not pressure.) - {{ $json['\\'Proven Winners\\' Ad Samples'] }}\nAnother set of ad copies from competitors for additional data - {{ $json['Ad Copies from Competitors'] }}\n\nCustomer Review - {{ $json['Customer Review (optional)'] }}\n\n\u26a0\ufe0f Key Guidelines to Follow:\nKeep it cool \u2013 Never sound desperate for a sale. Cool > Clear.\nLess is more \u2013 One-liner captions often perform best. Silence is power.\nBrand comes first \u2013 The tone should sound like it\u2019s from the brand\u2019s own Instagram, not a sales rep.\nDirect-response formats (problem \u2192 solution) rarely work in fashion.\nVisuals do the heavy lifting \u2013 Sometimes, the best copy is no copy. Keep that in mind.\nStay aligned with the fashion ecosystem \u2013 If it wouldn\u2019t be seen on a Dior, Moshi, or Reformation ad, don\u2019t say it here.\n\u2705 Deliverables:\n3\u20135 ad copy variations (60 characters to 90 words max)\nUse the format: Hook (optional) + Vibe Copy (brand voice) + Optional Tagline (if needed)\nKeep it minimal, editorial, and always in-brand.\n\n{{ $json['Attach Research Brief and other references'] }}\n"
            }
          ]
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "f36aa2d0-cdd9-4604-b6b0-3cc98426cfc7",
      "name": "For Problem Solution Brands",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        0,
        416
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=You are the \"Winning-Ad Generator,\" trained to write 3 ad copies designed for Meta or TikTok.\n\n\ud83d\udd39 Format: Hook + Benefits + Call to Action (Casual, benefit-driven, VoC language, fun emojis)\n\ud83d\udd39 Tone: Conversational, playful, Gen Z/Millennial-friendly\n\ud83d\udd39 Output: 3 ad variations, 60\u201390 words each\n\nHere\u2019s the product info:\n- Product Name: {{ $json['Product Name'] }}\n- Description/Product link: {{ $json['Product Page Link'] }}\n- Target Audience: {{ $json['Target Audience'] }}\n- Pain Points: {{ $json['Pain Points'] }}\n- Unique Selling Point: {{ $json['USP - 1 liner'] }}\n- Optional Customer Review: {{ $json['Customer Review (optional)'] }}\n - Previous successful ads - {{ $json['\\'Proven Winners\\' Ad Samples'] }}\n - Competitors' successful ads - {{ $json['Ad Copies from Competitors'] }}\n - Research Brief and other information - {{ $json['Attach Research Brief and other references'] }}\nUse one of these hook styles for each ad:\n1. Testimonial lead\n2. Pain point or \"ditch the old way\"\n3. Demographic call-out\n\nInclude emojis. End with hype + CTA."
            }
          ]
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "d0f1d89d-c6cc-4a39-b6f7-35d6f90373a0",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -480,
        208
      ],
      "parameters": {
        "options": {},
        "formTitle": "Create Ad Copies",
        "formFields": {
          "values": [
            {
              "fieldType": "dropdown",
              "fieldLabel": "Brand Name",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Fashion Brand"
                  },
                  {
                    "option": "Problem-Solution Brand"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "file",
              "fieldLabel": "Attach Research Brief and other references",
              "requiredField": true
            },
            {
              "fieldLabel": "Product Name",
              "requiredField": true
            },
            {
              "fieldLabel": "Product Page Link",
              "placeholder": "Paste product page link here",
              "requiredField": true
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "Target Audience",
              "requiredField": true
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "Pain Points"
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "USP - 1 liner",
              "requiredField": true
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "Customer Review (optional)"
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "'Proven Winners' Ad Samples",
              "requiredField": true
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "Ad Copies from Competitors",
              "requiredField": true
            }
          ]
        },
        "formDescription": "Create Winning Ad copies in seconds!"
      },
      "typeVersion": 2.2
    },
    {
      "id": "26d3885d-2b2a-4334-9387-7bf0c1de492b",
      "name": "Slack: Send and Review Ad Copies",
      "type": "n8n-nodes-base.slack",
      "position": [
        608,
        176
      ],
      "parameters": {
        "select": "channel",
        "message": "=Suggested Ad Copies for {{ $('On form submission').item.json['Product Name'] }} of {{ $('On form submission').item.json['Brand Name'] }}\n\n{{ $json.message.content }}",
        "options": {},
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "operation": "sendAndWait",
        "approvalOptions": {
          "values": {
            "approvalType": "double",
            "disapproveLabel": "Try again!"
          }
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "b45a3f11-9078-4eb9-b9bf-b4ffcdde47bd",
      "name": "If: Type of Brand",
      "type": "n8n-nodes-base.if",
      "position": [
        -224,
        208
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "87fd45fb-42d7-48d1-b435-48ed158a525e",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json['Brand Name'] }}",
              "rightValue": "Fashion Brand"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "06120531-7647-49d8-9312-42c4e95dadba",
      "name": "If: Ad Copy is Approve or not",
      "type": "n8n-nodes-base.if",
      "position": [
        816,
        176
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "4629180e-de2a-4cf2-b97b-744fdf2140ba",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.data.approved }}",
              "rightValue": "approved"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "613fa585-dc2f-4a7b-b86c-1b21f4181eaa",
      "name": "Slack: Congrats on your approve Ad Copies",
      "type": "n8n-nodes-base.slack",
      "position": [
        2896,
        160
      ],
      "parameters": {
        "text": "Congratulations! You now have your Ad Copies for {{ $('On form submission').item.json['Product Name'] }} of {{ $('On form submission').item.json['Brand Name'] }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "otherOptions": {}
      },
      "typeVersion": 2.3
    },
    {
      "id": "706f4e3f-d0c6-423c-9f55-31fc07ffc31a",
      "name": "Slack: Receive feedback for revision",
      "type": "n8n-nodes-base.slack",
      "position": [
        1056,
        464
      ],
      "parameters": {
        "select": "channel",
        "message": "Alright! Can you give us some feedback on the ad copies - what is off, what should be changed etc. and we will pass it to chatgpt? Click Respond now!",
        "options": {},
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "operation": "sendAndWait",
        "responseType": "freeText"
      },
      "typeVersion": 2.3
    },
    {
      "id": "b2b9acb7-e8de-4d86-9bf7-465ec2f405f2",
      "name": "OpenAI: Revise Ad Copies",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1760,
        480
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=The initial batch of ad copies for {{ $('If: Type of Brand').item.json['Product Name'] }} of {{ $('If: Type of Brand').item.json['Brand Name'] }} is NOT APPROVED. Our head of marketing is requesting for revision. \n\nHere's the feedback - {{ $json.data.text }}\n\nUse that feedback to generate another batch of 3-5 ad copies.\n\nYou may need the data previously influded on the initial ad request. Here you go:\nInitial Ad copies that needs to be revised - {{\n  $('For Fashion Brands').item?.json?.message?.content || \n  $('For Problem Solution Brands').item?.json?.message?.content\n}}\n\nProduct: {{ $('If: Type of Brand').item.json['Product Name'] }} of {{ $('If: Type of Brand').item.json['Brand Name'] }}\nProduct Link: {{ $('If: Type of Brand').item.json['Product Page Link'] }}\nTarget Audience: {{ $('If: Type of Brand').item.json['Target Audience'] }}\nPain Points: {{ $('If: Type of Brand').item.json['Pain Points'] }}\nUSP:{{ $('If: Type of Brand').item.json['USP - 1 liner'] }}\nCustomer Review: {{ $('If: Type of Brand').item.json['Customer Review (optional)'] }}\nProven Winner Ads:{{ $('If: Type of Brand').item.json['\\'Proven Winners\\' Ad Samples'] }}\nCompetitor winning ads:{{ $('If: Type of Brand').item.json['Ad Copies from Competitors'] }}\nResearch and other notes: {{ $('If: Type of Brand').item.json['Attach Research Brief and other references'][0].filename }}\n\n"
            }
          ]
        }
      },
      "executeOnce": false,
      "typeVersion": 1.8,
      "alwaysOutputData": true
    },
    {
      "id": "55fc1aa6-56a3-44c2-8c78-96783dd38938",
      "name": "Slack: Thank you for the feedback",
      "type": "n8n-nodes-base.slack",
      "position": [
        1280,
        256
      ],
      "parameters": {
        "text": "Thank you for your feedback... Currently working on the revisions...",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "otherOptions": {}
      },
      "typeVersion": 2.3
    },
    {
      "id": "d2c1f8f5-3208-4da2-9e9d-7a672ab832ec",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        2416,
        480
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "e8632a89-32d4-454f-bc06-8fab551151c6",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.data.approved }}",
              "rightValue": "approved"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "2d998128-7307-47e1-b595-370097ac0565",
      "name": "Slack: Send Revise Ad Copies",
      "type": "n8n-nodes-base.slack",
      "position": [
        2208,
        480
      ],
      "parameters": {
        "select": "channel",
        "message": "=Here's the new version of Ad copies \n\n {{ $json.message.content }}",
        "options": {},
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "operation": "sendAndWait",
        "approvalOptions": {
          "values": {
            "approvalType": "double",
            "disapproveLabel": "Try again!"
          }
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "227e34be-3865-4451-9385-015c0bd7d589",
      "name": "Edit Fields: Revision Counter Max 3",
      "type": "n8n-nodes-base.set",
      "position": [
        1280,
        464
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "90f59bde-b04b-4c41-b578-ca43102f3a29",
              "name": "revisionCount",
              "type": "number",
              "value": "={{ $json[\"revisionCount\"] ? $json[\"revisionCount\"] + 1 : 1 }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e7694ae4-8525-4158-8793-a57192db5682",
      "name": "If: Continue Revise or Stop",
      "type": "n8n-nodes-base.if",
      "position": [
        1504,
        464
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c2d54c5b-5e45-4135-b8ed-ada5abfb90ca",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{$json[\"revisionCount\"]}}",
              "rightValue": 3
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "1105ab26-1006-4dba-a9d3-d8112cca9246",
      "name": "Slack: Maxed Out Revision Count",
      "type": "n8n-nodes-base.slack",
      "position": [
        1760,
        256
      ],
      "parameters": {
        "text": "Too many revisions! Sorry, I wont be able to help you anymore. Please check with ChatGPT or Claude. ",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "otherOptions": {}
      },
      "typeVersion": 2.3
    },
    {
      "id": "e5633eb5-2b66-43f2-9bb5-ed7aa71f3501",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1168,
        -272
      ],
      "parameters": {
        "width": 784,
        "height": 880,
        "content": "# AI Ad Copy Generator with Approval Workflow\n\nThis workflow automates ad copy creation using AI, with built-in team review via Slack.\n\n## Who's it for\nMarketing teams, copywriters, and agencies who need to quickly generate and iterate on ad copies for Meta and TikTok campaigns. Perfect for brands that want AI-powered copy generation with human review and approval built into the workflow.\n\n## What it does\n- Collects brand and product information through a form\n- Uses AI to generate tailored ad copies based on brand type (Fashion or Problem-Solution)\n- Sends copies to Slack for team review and approval\n- Handles revision requests with feedback incorporation\n- Limits revisions to 3 rounds to maintain efficiency\n\n## How to set up\n1. Configure your OpenAI credentials in the OpenAI nodes\n2. Select your preferred GPT model in each OpenAI node\n3. Set up Slack integration and select your review channel in all Slack nodes\n4. Test the form to ensure file uploads work properly\n5. Run a test with sample data before going live\n\n## Requirements\n- OpenAI API access (GPT-3.5 or GPT-4)\n- Slack workspace with appropriate channel permissions\n- Self-hosted n8n instance (for file upload functionality)\n\n## How to customize\n- Adjust the AI prompts in OpenAI nodes to match your brand voice\n- Modify the revision limit in the \"Edit Fields: Revision Counter Max 3\" node\n- Add additional brand types in the form dropdown\n- Customize Slack messages to match your team's communication style"
      },
      "typeVersion": 1
    },
    {
      "id": "f0d82f05-10e6-4b24-9e8c-a461d052120d",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -544,
        336
      ],
      "parameters": {
        "color": 7,
        "height": 80,
        "content": "Step 1: Collect brand information and requirements"
      },
      "typeVersion": 1
    },
    {
      "id": "0f97bc32-395d-4f68-9f25-0795e30cbddf",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -96
      ],
      "parameters": {
        "color": 7,
        "height": 80,
        "content": "Step 2: Generate initial ad copies based on brand type"
      },
      "typeVersion": 1
    },
    {
      "id": "91b9902d-41b8-4594-81d9-d7b0f690546c",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        544,
        80
      ],
      "parameters": {
        "color": 7,
        "height": 80,
        "content": "Step 3: Team review and approval process"
      },
      "typeVersion": 1
    },
    {
      "id": "a108d24c-f51e-4c4c-9362-c7e910284f90",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        752,
        464
      ],
      "parameters": {
        "color": 7,
        "height": 80,
        "content": "Step 4: Revision loop (max 3 iterations)"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "d3901d5c-3c3f-493a-8d2d-ee72fe9d9294",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Slack: Congrats on your approve Ad Copies",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Slack: Receive feedback for revision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If: Type of Brand": {
      "main": [
        [
          {
            "node": "For Fashion Brands",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "For Problem Solution Brands",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "For Fashion Brands": {
      "main": [
        [
          {
            "node": "Slack: Send and Review Ad Copies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "If: Type of Brand",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI: Revise Ad Copies": {
      "main": [
        [
          {
            "node": "Slack: Send Revise Ad Copies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "For Problem Solution Brands": {
      "main": [
        [
          {
            "node": "Slack: Send and Review Ad Copies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If: Continue Revise or Stop": {
      "main": [
        [
          {
            "node": "Slack: Maxed Out Revision Count",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "OpenAI: Revise Ad Copies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack: Send Revise Ad Copies": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If: Ad Copy is Approve or not": {
      "main": [
        [
          {
            "node": "Slack: Congrats on your approve Ad Copies",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Slack: Receive feedback for revision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack: Send and Review Ad Copies": {
      "main": [
        [
          {
            "node": "If: Ad Copy is Approve or not",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields: Revision Counter Max 3": {
      "main": [
        [
          {
            "node": "If: Continue Revise or Stop",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack: Receive feedback for revision": {
      "main": [
        [
          {
            "node": "Slack: Thank you for the feedback",
            "type": "main",
            "index": 0
          },
          {
            "node": "Edit Fields: Revision Counter Max 3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

Marketing teams, copywriters, and agencies who need to quickly generate and iterate on ad copies for Meta and TikTok campaigns. Perfect for brands that want AI-powered copy generation with human review and approval built into the workflow.

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

More AI & RAG workflows → · Browse all categories →

Related workflows

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

AI & RAG

This workflow is an AI-powered lighting and look development pipeline designed for VFX production. It transforms a single lighting brief into multiple high-quality cinematic lighting references using

Form Trigger, HTTP Request, Google Drive +4
AI & RAG

Some use cases: "Speed-to-Lead" optimization, lead enrichment, automated prospect research. Ingestion: A lead submits their details (Name, Email, Website) via a form. Intelligent scraping: The workflo

Form Trigger, OpenAI, Airtable +2
AI & RAG

This workflow automates the "speed-to-lead" process for insurance agencies. It instantly triggers an AI voice call when a new lead comes in, qualifies their needs via conversation, and automatically g

Form Trigger, Airtable, HTTP Request +3
AI & RAG

Here is the template specification based on the provided workflow and guidelines.

Form Trigger, Google Sheets, HTTP Request +2
AI & RAG

Grain Real Estate Land Showcase v1. Uses formTrigger, httpRequest, openAi, emailSend. Event-driven trigger; 13 nodes.

Form Trigger, HTTP Request, OpenAI +3