{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Create relevant Meta ads with GPT-4o, OriginalVoices, and Google Sheets",
  "tags": [
    {
      "name": "Marketing"
    },
    {
      "name": "AI"
    },
    {
      "name": "Meta Ads"
    },
    {
      "name": "Copywriting"
    }
  ],
  "nodes": [
    {
      "id": "sticky-main-overview",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "color": 4,
        "width": 380,
        "height": 780,
        "content": "## Create relevant Meta ads with GPT-4o, OriginalVoices, and Google Sheets\nGenerate 50 ad variations **informed by audience insights**, then **validate with real human feedback** to identify the top 10.\n\n### How it works\n1. **Form** collects product details and target audience\n2. **AI gathers insights** from Digital Twins to understand your audience\n3. **Generate 50 variations** shaped by real human preferences\n4. **Digital Twins validate** each ad for resonance\n5. **Top 10 ranked** to Google Sheet with scores and feedback\n\n### Setup\n1. Connect **OpenAI API** credentials on Chat Model nodes\n2. Connect **Header Auth** on OriginalVoices node:\n   - Header: `X-Api-Key`\n   - Value: `YOUR_API_KEY`\n3. Connect **Google Sheets OAuth** credentials\n4. Create a Google Sheet with tab \"Results\"\n5. **Activate** the workflow\n\n### Customize\n- **Variation count**: Adjust agent prompt\n- **Validation criteria**: Modify Digital Twin questions\n- **Output format**: Add columns as needed\n\n### Need help?\nReach out on Discord (`vedad27`) or email `vedad@originalvoices.ai`"
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-trigger",
      "name": "Sticky Note Trigger",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        432,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 260,
        "height": 272,
        "content": "### 1. Input Form"
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-generate",
      "name": "Sticky Note Generate",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 468,
        "content": "### 2. Generate 50 Variations\nConnect OpenAI credentials"
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-validate",
      "name": "Sticky Note Validate",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1248,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 500,
        "height": 468,
        "content": "### 3. Filter & Validate\nConnect OriginalVoices credentials"
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-output",
      "name": "Sticky Note Output",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1792,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 292,
        "content": "### 4. Output to Sheet\nConnect Google Sheets credentials"
      },
      "typeVersion": 1
    },
    {
      "id": "form-trigger",
      "name": "Ad Brief Form",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        496,
        208
      ],
      "parameters": {
        "options": {},
        "formTitle": "Meta Ad Copy Generator",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Product/Brand Name",
              "placeholder": "e.g., Acme Fitness App",
              "requiredField": true
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "Product Description",
              "placeholder": "What does your product do? Key features?",
              "requiredField": true
            },
            {
              "fieldLabel": "Target Audience",
              "placeholder": "e.g., US women, 25-40, health-conscious, busy professionals",
              "requiredField": true
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "Key Benefits",
              "placeholder": "2-3 main value propositions (one per line)",
              "requiredField": true
            },
            {
              "fieldLabel": "Tone",
              "placeholder": "e.g., conversational, urgent, professional, playful",
              "requiredField": true
            },
            {
              "fieldLabel": "Landing Page URL",
              "placeholder": "https://... (optional, for context)"
            },
            {
              "fieldLabel": "Google Sheet URL",
              "placeholder": "https://docs.google.com/spreadsheets/d/...",
              "requiredField": true
            }
          ]
        },
        "formDescription": "Generate and validate Meta ad copy variations using AI and real human feedback."
      },
      "typeVersion": 2.2
    },
    {
      "id": "generate-variations",
      "name": "Generate 50 Variations",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        768,
        208
      ],
      "parameters": {
        "text": "=You are an expert Meta Ads copywriter. Generate 50 unique ad copy variations for the following product.\n\nPRODUCT INFO:\n- Name: {{ $json['Product/Brand Name'] }}\n- Description: {{ $json['Product Description'] }}\n- Target Audience: {{ $json['Target Audience'] }}\n- Key Benefits: {{ $json['Key Benefits'] }}\n- Tone: {{ $json['Tone'] }}\n{{ $json['Landing Page URL'] ? '- Landing Page: ' + $json['Landing Page URL'] : '' }}\n\nGENERATE 50 VARIATIONS using these angles (mix them up):\n1. **Benefit-focused** (10 variations) - Lead with the transformation/outcome\n2. **Problem-aware** (10 variations) - Acknowledge the pain point, offer solution\n3. **Social proof** (8 variations) - Imply popularity, results others have seen\n4. **Urgency/Scarcity** (7 variations) - Time-sensitive or limited availability\n5. **Curiosity/Question** (8 variations) - Open loops, make them want to know more\n6. **Direct/Bold** (7 variations) - Straightforward value proposition\n\nFor EACH variation provide:\n- primary_text: The main ad copy (2-4 sentences, first 125 chars are crucial as hook)\n- headline: Bold text below creative (under 40 chars, punchy)\n\nOutput ONLY a valid JSON array with 50 objects. No markdown, no explanation.\n\nExample format:\n[\n  {\"id\": 1, \"angle\": \"benefit\", \"primary_text\": \"...\", \"headline\": \"...\"},\n  {\"id\": 2, \"angle\": \"problem\", \"primary_text\": \"...\", \"headline\": \"...\"}\n]",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "openai-model",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        768,
        432
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o"
        },
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "parse-variations",
      "name": "Parse Variations",
      "type": "n8n-nodes-base.code",
      "position": [
        1056,
        208
      ],
      "parameters": {
        "jsCode": "const output = $input.first().json.output;\n// Strip markdown code blocks if present\nlet jsonStr = output;\nif (typeof output === 'string') {\n  jsonStr = output.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\n}\nconst variations = typeof jsonStr === 'string' ? JSON.parse(jsonStr) : jsonStr;\n\n// Pass along form data for later use\nconst formData = $('Ad Brief Form').first().json;\n\nreturn [{ \n  json: { \n    variations,\n    formData,\n    variationCount: variations.length\n  } \n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "validate-with-twins",
      "name": "Filter & Validate with Digital Twins",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1296,
        208
      ],
      "parameters": {
        "text": "=You are evaluating Meta ad copy variations with real human feedback.\n\nTARGET AUDIENCE: {{ $json.formData['Target Audience'] }}\n\nYou have access to the ask_twins tool which queries Digital Twins (AI representations of real people matching your target demographic).\n\nHere are 50 ad variations to evaluate:\n{{ JSON.stringify($json.variations, null, 2) }}\n\n---\n\nTASK: Use Digital Twins to identify the TOP 10 most compelling variations.\n\nSTEP 1: INITIAL FILTER\nUse ask_twins to find scroll-stoppers. \nCRITICAL: Digital Twins CANNOT see the variations - you MUST embed the full ad copy in your question.\n\nCall ask_twins with:\n- audience: \"{{ $json.formData['Target Audience'] }}\"\n- questions: Create 2-3 questions that embed batches of variations (e.g., embed 15-20 per question)\n  - Ask: \"Which of these ads would make you stop scrolling? [embed ads]\"\n  - Ask: \"Which headlines grab your attention? [embed headlines]\"\n\nSTEP 2: DEEP VALIDATION ON TOP 10\nFor the top 10 identified, use ask_twins again:\n- Embed the full primary_text + headline for each\n- Ask about: clarity, believability, purchase intent\n- Get specific feedback on what works and what doesn't\n\n---\n\nOUTPUT FORMAT:\nAfter both steps, output ONLY a JSON array of the top 10 ranked by resonance.\nNo markdown, no explanation - just the JSON.\n\n[\n  {\n    \"rank\": 1,\n    \"id\": <original id>,\n    \"primary_text\": \"...\",\n    \"headline\": \"...\",\n    \"angle\": \"...\",\n    \"resonance_score\": <1-10>,\n    \"feedback\": \"Why this resonated with the target audience\"\n  }\n]",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "openai-model-twins",
      "name": "OpenAI Chat Model1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1296,
        432
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o"
        },
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "ov-mcp-tool",
      "name": "OriginalVoices Digital Twins",
      "type": "@n8n/n8n-nodes-langchain.mcpClientTool",
      "position": [
        1440,
        432
      ],
      "parameters": {
        "options": {},
        "endpointUrl": "https://api.originalvoices.ai/mcp",
        "authentication": "headerAuth"
      },
      "typeVersion": 1.2
    },
    {
      "id": "parse-results",
      "name": "Parse Results",
      "type": "n8n-nodes-base.code",
      "position": [
        1600,
        208
      ],
      "parameters": {
        "jsCode": "const output = $input.first().json.output;\nconst formData = $('Parse Variations').first().json.formData;\n\n// Strip markdown code blocks if present\nlet jsonStr = output;\nif (typeof output === 'string') {\n  jsonStr = output.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\n}\nconst topAds = typeof jsonStr === 'string' ? JSON.parse(jsonStr) : jsonStr;\n\n// Extract sheet ID from URL\nconst sheetUrl = formData['Google Sheet URL'];\nconst sheetIdMatch = sheetUrl.match(/\\/d\\/([a-zA-Z0-9-_]+)/);\nconst sheetId = sheetIdMatch ? sheetIdMatch[1] : null;\n\nreturn [{ \n  json: { \n    topAds,\n    sheetId,\n    productName: formData['Product/Brand Name']\n  } \n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "format-for-sheets",
      "name": "Format for Sheets",
      "type": "n8n-nodes-base.code",
      "position": [
        1872,
        208
      ],
      "parameters": {
        "jsCode": "const topAds = $input.first().json.topAds;\nconst productName = $input.first().json.productName;\n\n// Convert array to individual rows for Google Sheets\nreturn topAds.map(ad => ({\n  json: {\n    'Rank': ad.rank,\n    'Primary Text': ad.primary_text,\n    'Headline': ad.headline,\n    'Angle': ad.angle,\n    'Resonance Score': ad.resonance_score,\n    'Feedback': ad.feedback,\n    'Product': productName\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "write-to-sheet",
      "name": "Write to Google Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2080,
        208
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Results"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Parse Results').first().json.sheetId }}"
        }
      },
      "typeVersion": 4.6
    }
  ],
  "connections": {
    "Ad Brief Form": {
      "main": [
        [
          {
            "node": "Generate 50 Variations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Results": {
      "main": [
        [
          {
            "node": "Format for Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Variations": {
      "main": [
        [
          {
            "node": "Filter & Validate with Digital Twins",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format for Sheets": {
      "main": [
        [
          {
            "node": "Write to Google Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Generate 50 Variations",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Filter & Validate with Digital Twins",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Generate 50 Variations": {
      "main": [
        [
          {
            "node": "Parse Variations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OriginalVoices Digital Twins": {
      "ai_tool": [
        [
          {
            "node": "Filter & Validate with Digital Twins",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Filter & Validate with Digital Twins": {
      "main": [
        [
          {
            "node": "Parse Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}